mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-17 04:51:53 +00:00
Try to direct edit texts - unsuccessful.
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
@@ -43,10 +42,13 @@ import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle;
|
||||
import com.jpexs.decompiler.flash.tags.dynamictext.Word;
|
||||
import com.jpexs.decompiler.flash.tags.enums.TextRenderMode;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParsedSymbol;
|
||||
import com.jpexs.decompiler.flash.tags.text.SymbolType;
|
||||
import com.jpexs.decompiler.flash.tags.text.TextAlign;
|
||||
import com.jpexs.decompiler.flash.tags.text.TextLexer;
|
||||
import com.jpexs.decompiler.flash.tags.text.TextParseException;
|
||||
import com.jpexs.decompiler.flash.tags.text.xml.XmlException;
|
||||
import com.jpexs.decompiler.flash.tags.text.xml.XmlLexer;
|
||||
import com.jpexs.decompiler.flash.tags.text.xml.XmlParsedSymbol;
|
||||
import com.jpexs.decompiler.flash.tags.text.xml.XmlSymbolType;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry;
|
||||
@@ -64,28 +66,22 @@ import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* DefineEditText tag - defines an editable text field.
|
||||
@@ -217,6 +213,154 @@ public class DefineEditTextTag extends TextTag {
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCharacterGlyph(int glyphPos) {
|
||||
List<TEXTRECORD> recs = getTextRecords(getSwf());
|
||||
int pos = 0;
|
||||
for (TEXTRECORD r : recs) {
|
||||
if (r instanceof AdvancedTextRecord) {
|
||||
AdvancedTextRecord atr = (AdvancedTextRecord) r;
|
||||
for (int htmlSourcePos : atr.htmlSourcePositions) {
|
||||
if (pos == glyphPos) {
|
||||
char character = initialText.charAt(htmlSourcePos);
|
||||
if (character == '&') {
|
||||
int semiPos = initialText.indexOf(";", htmlSourcePos);
|
||||
if (semiPos != -1) {
|
||||
initialText = initialText.substring(0, htmlSourcePos) + initialText.substring(semiPos + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
initialText = initialText.substring(0, htmlSourcePos) + initialText.substring(htmlSourcePos + 1);
|
||||
packHtml();
|
||||
setModified(true);
|
||||
return;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void packHtml() {
|
||||
try {
|
||||
XmlLexer lexer = new XmlLexer(new StringReader(initialText));
|
||||
XmlParsedSymbol s = lexer.yylex();
|
||||
String tagName = null;
|
||||
StringBuilder result = new StringBuilder();
|
||||
StringBuilder cached = new StringBuilder();
|
||||
boolean hasCharacter = false;
|
||||
while (s.type != XmlSymbolType.EOF) {
|
||||
if (s.type == XmlSymbolType.TAG_OPEN) {
|
||||
if (tagName != null) {
|
||||
result.append(cached.toString());
|
||||
}
|
||||
tagName = (String) s.value;
|
||||
cached = new StringBuilder();
|
||||
cached.append(s.rawText);
|
||||
hasCharacter = false;
|
||||
} else if (s.type == XmlSymbolType.TAG_CLOSE) {
|
||||
if (tagName != null) {
|
||||
if ("font".equals(tagName) && !hasCharacter) {
|
||||
//ignore
|
||||
} else {
|
||||
cached.append(s.rawText);
|
||||
result.append(cached.toString());
|
||||
}
|
||||
} else {
|
||||
result.append(s.rawText);
|
||||
}
|
||||
tagName = null;
|
||||
} else if (s.type == XmlSymbolType.ATTRIBUTE
|
||||
|| s.type == XmlSymbolType.ATTRIBUTE_VALUE
|
||||
|| s.type == XmlSymbolType.TAG_OPEN_END) {
|
||||
if (tagName != null) {
|
||||
cached.append(s.rawText);
|
||||
} else {
|
||||
result.append(s.rawText);
|
||||
}
|
||||
} else if (s.type == XmlSymbolType.CHARACTER) {
|
||||
hasCharacter = true;
|
||||
if (tagName != null) {
|
||||
cached.append(s.rawText);
|
||||
} else {
|
||||
result.append(s.rawText);
|
||||
}
|
||||
} else {
|
||||
if (tagName != null) {
|
||||
cached.append(s.rawText);
|
||||
} else {
|
||||
result.append(s.rawText);
|
||||
}
|
||||
}
|
||||
s = lexer.yylex();
|
||||
}
|
||||
initialText = result.toString();
|
||||
} catch (IOException | XmlException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertCharacterGlyph(int glyphPos, char character) {
|
||||
List<TEXTRECORD> recs = getTextRecords(getSwf());
|
||||
int pos = 0;
|
||||
String str = "" + character;
|
||||
switch (character) {
|
||||
case '&':
|
||||
str = "&";
|
||||
break;
|
||||
case '<':
|
||||
str = "<";
|
||||
break;
|
||||
case '>':
|
||||
str = ">";
|
||||
break;
|
||||
case '\u00A0':
|
||||
str = " ";
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case '"':
|
||||
str = """;
|
||||
break;
|
||||
case '\'':
|
||||
str = "'";
|
||||
break;
|
||||
*/
|
||||
|
||||
int lastHtmlSourcePos = -1;
|
||||
for (TEXTRECORD r : recs) {
|
||||
if (r instanceof AdvancedTextRecord) {
|
||||
AdvancedTextRecord atr = (AdvancedTextRecord) r;
|
||||
for (int htmlSourcePos : atr.htmlSourcePositions) {
|
||||
if (pos == glyphPos) {
|
||||
initialText = initialText.substring(0, htmlSourcePos) + str + initialText.substring(htmlSourcePos);
|
||||
setModified(true);
|
||||
return;
|
||||
}
|
||||
lastHtmlSourcePos = htmlSourcePos;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastHtmlSourcePos == -1) {
|
||||
initialText = str + initialText;
|
||||
return;
|
||||
}
|
||||
|
||||
int newHtmlSourcePos = lastHtmlSourcePos + 1;
|
||||
char prevCharacter = initialText.charAt(lastHtmlSourcePos);
|
||||
if (character == '&') {
|
||||
int semiPos = initialText.indexOf(";", lastHtmlSourcePos);
|
||||
if (semiPos != -1) {
|
||||
newHtmlSourcePos = semiPos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
initialText = initialText.substring(0, newHtmlSourcePos) + str + initialText.substring(newHtmlSourcePos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
@@ -402,107 +546,24 @@ public class DefineEditTextTag extends TextTag {
|
||||
style.leftMargin = leftMargin;
|
||||
final List<CharacterWithStyle> ret = new ArrayList<>();
|
||||
if (html) {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser saxParser;
|
||||
//SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
//SAXParser saxParser;
|
||||
final Stack<TextStyle> styles = new Stack<>();
|
||||
styles.add(style);
|
||||
try {
|
||||
/*try {
|
||||
saxParser = factory.newSAXParser();
|
||||
DefaultHandler handler = new DefaultHandler() {
|
||||
|
||||
private Locator locator;
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
TextStyle style = styles.peek();
|
||||
switch (qName) {
|
||||
case "p":
|
||||
// todo: parse the following attribute:
|
||||
// align
|
||||
break;
|
||||
case "a":
|
||||
// todo: handle link - href, target attributes
|
||||
break;
|
||||
case "b":
|
||||
style = style.clone();
|
||||
style.bold = true;
|
||||
styles.add(style);
|
||||
break;
|
||||
case "i":
|
||||
style = style.clone();
|
||||
style.italic = true;
|
||||
styles.add(style);
|
||||
break;
|
||||
case "u":
|
||||
style = style.clone();
|
||||
style.underlined = true;
|
||||
styles.add(style);
|
||||
break;
|
||||
case "font":
|
||||
style = style.clone();
|
||||
String color = unescape(attributes.getValue("color"));
|
||||
if (color != null) {
|
||||
if (color.startsWith("#")) {
|
||||
try {
|
||||
if (color.length() == 7) { //#rrggbb
|
||||
style.textColor = new RGBA(Color.decode(color));
|
||||
} else if (color.length() == 9) { //#aarrggbb
|
||||
style.textColor = RGBA.fromHexARGB(color);
|
||||
style.textColor.alpha = 255; //no alpha is allowed
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
//do not change textColor
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
String size = unescape(attributes.getValue("size"));
|
||||
if (size != null && size.length() > 0) {
|
||||
try {
|
||||
char firstChar = size.charAt(0);
|
||||
if (firstChar != '+' && firstChar != '-') {
|
||||
int fontSize = Integer.parseInt(size);
|
||||
style.fontHeight = (int) Math.round(fontSize * SWF.unitDivisor);
|
||||
} else {
|
||||
int fontSizeDelta = (int) Math.round(Integer.parseInt(size.substring(1)) * SWF.unitDivisor);
|
||||
if (firstChar == '+') {
|
||||
style.fontHeight = style.fontHeight + fontSizeDelta;
|
||||
} else {
|
||||
style.fontHeight = style.fontHeight - fontSizeDelta;
|
||||
}
|
||||
}
|
||||
style.fontLeading = leading;
|
||||
} catch (NumberFormatException nfe) {
|
||||
//do not change fontHeight or leading
|
||||
}
|
||||
}
|
||||
String face = unescape(attributes.getValue("face"));
|
||||
|
||||
if (face != null && face.length() > 0) {
|
||||
style.fontFace = face;
|
||||
}
|
||||
|
||||
String letterspacing = unescape(attributes.getValue("letterSpacing"));
|
||||
if (letterspacing != null && letterspacing.length() > 0) {
|
||||
try {
|
||||
style.letterSpacing = Double.parseDouble(letterspacing);
|
||||
} catch (NumberFormatException nfe) {
|
||||
//do not change letterSpacing
|
||||
}
|
||||
}
|
||||
|
||||
String kerning = unescape(attributes.getValue("kerning"));
|
||||
if (kerning != null && kerning.length() > 0) {
|
||||
style.kerning = kerning.equals("1");
|
||||
}
|
||||
|
||||
styles.add(style);
|
||||
break;
|
||||
case "br":
|
||||
case "sbr": // what's this?
|
||||
CharacterWithStyle cs = new CharacterWithStyle();
|
||||
cs.character = '\n';
|
||||
cs.style = style;
|
||||
ret.add(cs);
|
||||
break;
|
||||
}
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
this.locator = locator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Map<String, String> attributes) throws SAXException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -555,33 +616,209 @@ public class DefineEditTextTag extends TextTag {
|
||||
addCharacters(ret, txt, style);
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
str = str.replace(" ", "/{entity-nbsp}");
|
||||
str = str.replace("<", "/{entity-lt}");
|
||||
str = str.replace(">", "/{entity-gt}");
|
||||
str = str.replace(""", "/{entity-quot}");
|
||||
str = str.replace("&", "/{entity-amp}");
|
||||
str = str.replace("'", "/{entity-apos}");
|
||||
str = str.replace("&", "&");
|
||||
XmlLexer lexer = new XmlLexer(new StringReader(str));
|
||||
try {
|
||||
XmlParsedSymbol s = lexer.yylex();
|
||||
boolean inOpenTag = false;
|
||||
String attributeName = null;
|
||||
String tagName = null;
|
||||
Map<String, String> attributes = new LinkedHashMap<>();
|
||||
loops:
|
||||
while (s.type != XmlSymbolType.EOF) {
|
||||
switch (s.type) {
|
||||
case TAG_OPEN:
|
||||
inOpenTag = true;
|
||||
attributeName = null;
|
||||
tagName = (String) s.value;
|
||||
attributes.clear();
|
||||
break;
|
||||
case ATTRIBUTE:
|
||||
attributeName = (String) s.value;
|
||||
break;
|
||||
case ATTRIBUTE_VALUE:
|
||||
if (attributeName == null) {
|
||||
//Error
|
||||
break loops;
|
||||
}
|
||||
attributes.put(attributeName, unescape((String) s.value));
|
||||
break;
|
||||
case TAG_OPEN_END:
|
||||
style = styles.peek();
|
||||
switch (tagName) {
|
||||
case "p":
|
||||
// todo: parse the following attribute:
|
||||
// align
|
||||
break;
|
||||
case "a":
|
||||
// todo: handle link - href, target attributes
|
||||
break;
|
||||
case "b":
|
||||
style = style.clone();
|
||||
style.bold = true;
|
||||
styles.add(style);
|
||||
break;
|
||||
case "i":
|
||||
style = style.clone();
|
||||
style.italic = true;
|
||||
styles.add(style);
|
||||
break;
|
||||
case "u":
|
||||
style = style.clone();
|
||||
style.underlined = true;
|
||||
styles.add(style);
|
||||
break;
|
||||
case "font":
|
||||
style = style.clone();
|
||||
String color = attributes.get("color");
|
||||
if (color != null) {
|
||||
if (color.startsWith("#")) {
|
||||
try {
|
||||
if (color.length() == 7) { //#rrggbb
|
||||
style.textColor = new RGBA(Color.decode(color));
|
||||
} else if (color.length() == 9) { //#aarrggbb
|
||||
style.textColor = RGBA.fromHexARGB(color);
|
||||
style.textColor.alpha = 255; //no alpha is allowed
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
//do not change textColor
|
||||
}
|
||||
|
||||
str = "<!DOCTYPE html [\n"
|
||||
+ "]><root>" + str + "</root>";
|
||||
}
|
||||
}
|
||||
String size = attributes.get("size");
|
||||
if (size != null && size.length() > 0) {
|
||||
try {
|
||||
char firstChar = size.charAt(0);
|
||||
if (firstChar != '+' && firstChar != '-') {
|
||||
int fontSize = Integer.parseInt(size);
|
||||
style.fontHeight = (int) Math.round(fontSize * SWF.unitDivisor);
|
||||
} else {
|
||||
int fontSizeDelta = (int) Math.round(Integer.parseInt(size.substring(1)) * SWF.unitDivisor);
|
||||
if (firstChar == '+') {
|
||||
style.fontHeight = style.fontHeight + fontSizeDelta;
|
||||
} else {
|
||||
style.fontHeight = style.fontHeight - fontSizeDelta;
|
||||
}
|
||||
}
|
||||
style.fontLeading = leading;
|
||||
} catch (NumberFormatException nfe) {
|
||||
//do not change fontHeight or leading
|
||||
}
|
||||
}
|
||||
String face = attributes.get("face");
|
||||
|
||||
if (face != null && face.length() > 0) {
|
||||
style.fontFace = face;
|
||||
}
|
||||
|
||||
String letterspacing = attributes.get("letterSpacing");
|
||||
if (letterspacing != null && letterspacing.length() > 0) {
|
||||
try {
|
||||
style.letterSpacing = Double.parseDouble(letterspacing);
|
||||
} catch (NumberFormatException nfe) {
|
||||
//do not change letterSpacing
|
||||
}
|
||||
}
|
||||
|
||||
String kerning = attributes.get("kerning");
|
||||
if (kerning != null && kerning.length() > 0) {
|
||||
style.kerning = kerning.equals("1");
|
||||
}
|
||||
|
||||
styles.add(style);
|
||||
break;
|
||||
case "br":
|
||||
case "sbr": // what's this?
|
||||
CharacterWithStyle cs = new CharacterWithStyle();
|
||||
cs.character = '\n';
|
||||
cs.style = style;
|
||||
ret.add(cs);
|
||||
break;
|
||||
}
|
||||
tagName = null;
|
||||
break;
|
||||
case TAG_CLOSE:
|
||||
tagName = (String) s.value;
|
||||
switch (tagName) {
|
||||
case "b":
|
||||
case "i":
|
||||
case "u":
|
||||
case "font":
|
||||
styles.pop();
|
||||
break;
|
||||
case "p":
|
||||
style = styles.peek();
|
||||
CharacterWithStyle cs = new CharacterWithStyle();
|
||||
cs.character = '\n';
|
||||
cs.style = style;
|
||||
ret.add(cs);
|
||||
break;
|
||||
}
|
||||
tagName = null;
|
||||
break;
|
||||
|
||||
case ENTITY:
|
||||
case CHARACTER:
|
||||
String txt = (String) s.value;
|
||||
if (s.type == XmlSymbolType.ENTITY) {
|
||||
txt = unescape("&" + txt + ";");
|
||||
}
|
||||
style = styles.peek();
|
||||
if (style.fontFace != null && useOutlines) {
|
||||
CharacterTag ct = swf.getCharacterByExportName(style.fontFace);
|
||||
if (ct != null && (ct instanceof FontTag)) {
|
||||
style.font = (FontTag) ct;
|
||||
} else {
|
||||
style.font = swf.getFontByNameInTag(style.fontFace, style.bold, style.italic);
|
||||
}
|
||||
if (style.font == null) {
|
||||
style.fontFace = null;
|
||||
}
|
||||
}
|
||||
addCharacters(ret, txt, style, s.position);
|
||||
break;
|
||||
}
|
||||
s = lexer.yylex();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
//Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (XmlException ex) {
|
||||
//Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
//ex.printStackTrace();
|
||||
}
|
||||
/*
|
||||
str = str.replace(" ", "/{entity-nbsp}");
|
||||
str = str.replace("<", "/{entity-lt}");
|
||||
str = str.replace(">", "/{entity-gt}");
|
||||
str = str.replace(""", "/{entity-quot}");
|
||||
str = str.replace("&", "/{entity-amp}");
|
||||
str = str.replace("'", "/{entity-apos}");
|
||||
str = str.replace("&", "&");
|
||||
|
||||
str = "<!DOCTYPE html [\n"
|
||||
+ "]><root>" + str + "</root>";
|
||||
saxParser.parse(new ByteArrayInputStream(str.getBytes(Utf8Helper.charset)), handler);
|
||||
} catch (ParserConfigurationException | SAXException | IOException ex) {
|
||||
Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, "Error parsing text " + getCharacterId(), ex);
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
addCharacters(ret, str, style);
|
||||
addCharacters(ret, str, style, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void addCharacters(List<CharacterWithStyle> list, String str, TextStyle style) {
|
||||
private void addCharacters(List<CharacterWithStyle> list, String str, TextStyle style, int position) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char ch = str.charAt(i);
|
||||
CharacterWithStyle cs = new CharacterWithStyle();
|
||||
cs.character = ch;
|
||||
cs.style = style;
|
||||
if (position > -1) {
|
||||
cs.htmlSourcePosition = position + i;
|
||||
}
|
||||
list.add(cs);
|
||||
}
|
||||
}
|
||||
@@ -705,7 +942,7 @@ public class DefineEditTextTag extends TextTag {
|
||||
switch (s.type) {
|
||||
case PARAMETER_IDENTIFIER:
|
||||
String paramName = (String) s.value;
|
||||
s = lexer.yylex();
|
||||
s = lexer.yylex();
|
||||
String paramValue = (String) s.value;
|
||||
switch (paramName) {
|
||||
case "xmin":
|
||||
@@ -1137,7 +1374,7 @@ public class DefineEditTextTag extends TextTag {
|
||||
ge.glyphAdvance += font.getCharKerningAdjustment(c, nextChar) / font.getDivider();
|
||||
}
|
||||
}
|
||||
textModel.addGlyph(c, ge);
|
||||
textModel.addGlyph(c, ge, cs.htmlSourcePosition);
|
||||
if (Character.isWhitespace(c)) {
|
||||
lastWasWhiteSpace = true;
|
||||
}
|
||||
@@ -1330,8 +1567,10 @@ public class DefineEditTextTag extends TextTag {
|
||||
tr2.yOffset = yOffset;
|
||||
}
|
||||
tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size());
|
||||
tr2.htmlSourcePositions = new ArrayList<>(tr.glyphEntries.size());
|
||||
for (GlyphCharacter ge : tr.glyphEntries) {
|
||||
tr2.glyphEntries.add(ge.glyphEntry);
|
||||
tr2.htmlSourcePositions.add(ge.htmlSourcePosition);
|
||||
}
|
||||
allTextRecords.add(tr2);
|
||||
}
|
||||
@@ -1353,4 +1592,17 @@ public class DefineEditTextTag extends TextTag {
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String unescape(String txt) {
|
||||
if (txt == null) {
|
||||
return null;
|
||||
}
|
||||
txt = txt.replace(" ", "\u00A0");
|
||||
txt = txt.replace("<", "<");
|
||||
txt = txt.replace(">", ">");
|
||||
txt = txt.replace(""", "\"");
|
||||
txt = txt.replace("&", "&");
|
||||
txt = txt.replace("'", "'");
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class DefineTextTag extends StaticTextTag {
|
||||
public DefineTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTextNum() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
@@ -55,11 +56,21 @@ public class RenderContext {
|
||||
*/
|
||||
public TextTag mouseOverText;
|
||||
|
||||
/**
|
||||
* Absolute matrix of mouse over text position
|
||||
*/
|
||||
public Matrix mouseOverTextAbsMatrix;
|
||||
|
||||
/**
|
||||
* Selection text tag
|
||||
*/
|
||||
public TextTag selectionText;
|
||||
|
||||
/**
|
||||
* Selection text abs matrix
|
||||
*/
|
||||
public Matrix selectionAbsMatrix;
|
||||
|
||||
/**
|
||||
* Text selection start
|
||||
*/
|
||||
|
||||
@@ -125,6 +125,14 @@ public abstract class StaticTextTag extends TextTag {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertCharacterGlyph(int glyphPos, char character) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCharacterGlyph(int glyphPos) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
|
||||
@@ -92,6 +92,19 @@ public abstract class TextTag extends DrawableTag {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts character at the given position.
|
||||
* @param glyphPos Glyph position
|
||||
* @param character Character
|
||||
*/
|
||||
public abstract void insertCharacterGlyph(int glyphPos, char character);
|
||||
|
||||
/**
|
||||
* Removes character glyph at the given position
|
||||
* @param glyphPos Glyph position
|
||||
*/
|
||||
public abstract void removeCharacterGlyph(int glyphPos);
|
||||
|
||||
/**
|
||||
* Gets text matrix.
|
||||
* @return Text matrix
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags.dynamictext;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Text record with font class.
|
||||
@@ -27,6 +28,8 @@ import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
public class AdvancedTextRecord extends TEXTRECORD {
|
||||
public String fontClass = null;
|
||||
|
||||
public List<Integer> htmlSourcePositions = null;
|
||||
|
||||
@Override
|
||||
public FontTag getFont(SWF swf) {
|
||||
if (fontClass != null) {
|
||||
|
||||
@@ -32,4 +32,9 @@ public class CharacterWithStyle {
|
||||
* Style
|
||||
*/
|
||||
public TextStyle style;
|
||||
|
||||
/**
|
||||
* Position in HTML source
|
||||
*/
|
||||
public int htmlSourcePosition = -1;
|
||||
}
|
||||
|
||||
@@ -58,14 +58,15 @@ public class DynamicTextModel {
|
||||
* Add glyph.
|
||||
* @param character Character
|
||||
* @param glyphEntry Glyph entry
|
||||
* @param htmlSourcePosition Position in HTML source
|
||||
*/
|
||||
public void addGlyph(char character, GLYPHENTRY glyphEntry) {
|
||||
public void addGlyph(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
|
||||
|
||||
if (paragraph == null) {
|
||||
paragraph = new Paragraph(this);
|
||||
paragraphs.add(paragraph);
|
||||
}
|
||||
paragraph.addGlyph(character, glyphEntry);
|
||||
paragraph.addGlyph(character, glyphEntry, htmlSourcePosition);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,16 +34,23 @@ public class GlyphCharacter {
|
||||
* Character
|
||||
*/
|
||||
public char character;
|
||||
|
||||
/**
|
||||
* Position in HTML source
|
||||
*/
|
||||
public int htmlSourcePosition = -1;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param character Character
|
||||
* @param glyphEntry Glyph entry
|
||||
* @param htmlSourcePosition Position in HTML source
|
||||
*/
|
||||
public GlyphCharacter(char character, GLYPHENTRY glyphEntry) {
|
||||
public GlyphCharacter(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
|
||||
|
||||
this.character = character;
|
||||
this.glyphEntry = glyphEntry;
|
||||
this.htmlSourcePosition = htmlSourcePosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,14 +60,15 @@ public class Paragraph {
|
||||
* Add glyph.
|
||||
* @param character Character
|
||||
* @param glyphEntry Glyph entry
|
||||
* @param htmlSourcePosition Position in HTML source
|
||||
*/
|
||||
public void addGlyph(char character, GLYPHENTRY glyphEntry) {
|
||||
public void addGlyph(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
|
||||
|
||||
if (word == null) {
|
||||
word = new Word(model);
|
||||
words.add(word);
|
||||
}
|
||||
word.addGlyph(character, glyphEntry);
|
||||
word.addGlyph(character, glyphEntry, htmlSourcePosition);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,15 +60,16 @@ public class Word {
|
||||
* Adds glyph.
|
||||
* @param character Character
|
||||
* @param glyphEntry Glyph entry
|
||||
* @param htmlSourcePosition Position in HTML source
|
||||
*/
|
||||
public void addGlyph(char character, GLYPHENTRY glyphEntry) {
|
||||
public void addGlyph(char character, GLYPHENTRY glyphEntry, int htmlSourcePosition) {
|
||||
|
||||
if (record == null) {
|
||||
record = new SameStyleTextRecord();
|
||||
record.style = model.style;
|
||||
records.add(record);
|
||||
}
|
||||
record.glyphEntries.add(new GlyphCharacter(character, glyphEntry));
|
||||
record.glyphEntries.add(new GlyphCharacter(character, glyphEntry, htmlSourcePosition));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2025 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.text.xml;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class XmlException extends Exception {
|
||||
public XmlException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,744 @@
|
||||
/* The following code was generated by JFlex 1.6.0 */
|
||||
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.jpexs.decompiler.flash.tags.text.xml;
|
||||
|
||||
|
||||
/**
|
||||
* This class is a scanner generated by
|
||||
* <a href="http://www.jflex.de/">JFlex</a> 1.6.0
|
||||
* from the specification file <tt>C:/Dropbox/Programovani/JavaSE/FFDec/libsrc/ffdec_lib/lexers/text_xml.flex</tt>
|
||||
*/
|
||||
public final class XmlLexer {
|
||||
|
||||
/** This character denotes the end of file */
|
||||
public static final int YYEOF = -1;
|
||||
|
||||
/** initial size of the lookahead buffer */
|
||||
private static final int ZZ_BUFFERSIZE = 16384;
|
||||
|
||||
/** lexical states */
|
||||
public static final int YYINITIAL = 0;
|
||||
public static final int COMMENT = 2;
|
||||
public static final int CDATA = 4;
|
||||
public static final int TAG = 6;
|
||||
public static final int INSTR = 8;
|
||||
|
||||
/**
|
||||
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
|
||||
* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
|
||||
* at the beginning of a line
|
||||
* l is of the form l = 2*k, k a non negative integer
|
||||
*/
|
||||
private static final int ZZ_LEXSTATE[] = {
|
||||
0, 0, 1, 1, 2, 2, 3, 3, 4, 4
|
||||
};
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
*/
|
||||
private static final String ZZ_CMAP_PACKED =
|
||||
"\11\0\1\1\1\3\1\33\1\33\1\2\22\0\1\1\1\7\1\26"+
|
||||
"\1\31\2\0\1\4\1\27\5\0\1\10\1\13\1\24\12\14\1\11"+
|
||||
"\1\30\1\6\1\25\1\5\1\15\1\0\1\21\1\11\1\17\1\20"+
|
||||
"\1\11\16\11\1\22\6\11\1\16\1\0\1\23\1\0\1\11\1\0"+
|
||||
"\32\12\12\0\1\33\61\0\1\13\10\0\27\0\1\0\37\0\1\0"+
|
||||
"\u0208\0\160\0\16\0\1\0\u02e1\0\12\32\206\0\12\32\306\0\12\32"+
|
||||
"\u019c\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32"+
|
||||
"\166\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32\166\0\12\32"+
|
||||
"\140\0\12\32\166\0\12\32\106\0\12\32\u0116\0\12\32\106\0\12\32"+
|
||||
"\146\0\u06e0\0\12\32\46\0\12\32\u012c\0\12\32\200\0\12\32\246\0"+
|
||||
"\12\32\6\0\12\32\266\0\12\32\126\0\12\32\206\0\12\32\6\0"+
|
||||
"\12\32\u03a6\0\14\0\2\0\32\0\1\33\1\33\27\0\57\0\u0120\0"+
|
||||
"\u0a70\0\u03f0\0\21\0\u761f\0\12\32\u02a6\0\12\32\46\0\12\32\306\0"+
|
||||
"\12\32\26\0\12\32\126\0\12\32\u0196\0\12\32\u2c06\0\u0800\0\u1000\0"+
|
||||
"\u0900\0\u04d0\0\40\0\u0120\0\12\32\344\0\u04a2\0\12\32\u0bbc\0\12\32"+
|
||||
"\200\0\12\32\74\0\12\32\220\0\12\32\u0116\0\12\32\u01d6\0\12\32"+
|
||||
"\u0176\0\12\32\146\0\12\32\u0216\0\12\32\u5176\0\12\32\346\0\12\32"+
|
||||
"\u6c74\0\62\32\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\u280f\0";
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
*/
|
||||
private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
|
||||
|
||||
/**
|
||||
* Translates DFA states to action switch labels.
|
||||
*/
|
||||
private static final int [] ZZ_ACTION = zzUnpackAction();
|
||||
|
||||
private static final String ZZ_ACTION_PACKED_0 =
|
||||
"\5\0\1\1\4\2\1\0\2\2\1\0\1\2\1\3"+
|
||||
"\1\4\5\2\3\0\1\5\7\0\1\6\1\7\1\0"+
|
||||
"\1\10\1\0\1\11\1\12\3\0\1\13\2\0\1\14"+
|
||||
"\1\0\1\15\1\16\1\17\2\0\1\20\1\21\1\22"+
|
||||
"\4\0\1\23";
|
||||
|
||||
private static int [] zzUnpackAction() {
|
||||
int [] result = new int[61];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackAction(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates a state to a row index in the transition table
|
||||
*/
|
||||
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
|
||||
|
||||
private static final String ZZ_ROWMAP_PACKED_0 =
|
||||
"\0\0\0\34\0\70\0\124\0\160\0\214\0\250\0\304"+
|
||||
"\0\340\0\374\0\374\0\u0118\0\u0134\0\u0134\0\u0150\0\u016c"+
|
||||
"\0\304\0\u0188\0\u01a4\0\u01c0\0\u01dc\0\u01f8\0\u0214\0\u0230"+
|
||||
"\0\u024c\0\u0268\0\u0284\0\u02a0\0\u02bc\0\u02d8\0\u02f4\0\u0310"+
|
||||
"\0\u0188\0\304\0\304\0\u01c0\0\304\0\u01dc\0\304\0\304"+
|
||||
"\0\u032c\0\u0348\0\u0364\0\u0380\0\u039c\0\u03b8\0\304\0\u03d4"+
|
||||
"\0\304\0\304\0\304\0\u03f0\0\u040c\0\304\0\304\0\304"+
|
||||
"\0\u0428\0\u0444\0\u0460\0\u047c\0\304";
|
||||
|
||||
private static int [] zzUnpackRowMap() {
|
||||
int [] result = new int[61];
|
||||
int offset = 0;
|
||||
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackRowMap(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int high = packed.charAt(i++) << 16;
|
||||
result[j++] = high | packed.charAt(i++);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* The transition table of the DFA
|
||||
*/
|
||||
private static final int [] ZZ_TRANS = zzUnpackTrans();
|
||||
|
||||
private static final String ZZ_TRANS_PACKED_0 =
|
||||
"\4\6\1\7\1\10\1\11\25\6\2\12\1\13\5\12"+
|
||||
"\1\14\22\12\1\13\2\15\1\16\20\15\1\17\7\15"+
|
||||
"\1\16\1\10\3\20\1\10\1\21\3\10\2\22\4\10"+
|
||||
"\4\22\1\10\1\23\1\10\1\24\1\25\3\10\1\0"+
|
||||
"\1\10\3\20\5\10\2\22\2\10\1\26\1\10\4\22"+
|
||||
"\3\10\1\24\1\25\3\10\1\0\4\6\3\0\25\6"+
|
||||
"\12\0\1\27\16\0\1\30\45\0\1\31\1\0\2\32"+
|
||||
"\2\0\1\33\1\0\4\32\1\0\1\34\7\0\10\13"+
|
||||
"\1\35\33\13\1\36\23\13\23\16\1\37\33\16\1\40"+
|
||||
"\10\16\1\0\3\20\40\0\5\41\2\0\4\41\2\0"+
|
||||
"\1\42\13\0\1\43\26\0\2\44\2\0\22\44\1\45"+
|
||||
"\5\44\2\46\2\0\23\46\1\45\4\46\5\0\1\47"+
|
||||
"\40\0\1\27\15\0\1\50\17\0\1\51\15\0\1\51"+
|
||||
"\11\0\1\52\5\0\1\53\25\0\5\32\2\0\4\32"+
|
||||
"\22\0\2\54\4\0\4\54\22\0\2\55\4\0\4\55"+
|
||||
"\11\0\10\13\1\56\30\13\1\57\2\13\1\56\23\13"+
|
||||
"\23\16\1\60\15\16\1\61\15\16\1\60\10\16\14\0"+
|
||||
"\1\51\13\0\1\62\1\0\1\51\11\0\1\63\42\0"+
|
||||
"\1\64\24\0\5\54\2\0\4\54\12\0\3\65\1\0"+
|
||||
"\1\66\2\0\5\55\2\0\4\55\11\0\5\13\1\67"+
|
||||
"\2\13\1\56\23\13\5\16\1\70\15\16\1\60\10\16"+
|
||||
"\20\0\1\71\14\0\3\65\1\0\1\66\47\0\1\72"+
|
||||
"\34\0\1\73\32\0\1\74\30\0\1\75\15\0";
|
||||
|
||||
private static int [] zzUnpackTrans() {
|
||||
int [] result = new int[1176];
|
||||
int offset = 0;
|
||||
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackTrans(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
value--;
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/* error codes */
|
||||
private static final int ZZ_UNKNOWN_ERROR = 0;
|
||||
private static final int ZZ_NO_MATCH = 1;
|
||||
private static final int ZZ_PUSHBACK_2BIG = 2;
|
||||
|
||||
/* error messages for the codes above */
|
||||
private static final String ZZ_ERROR_MSG[] = {
|
||||
"Unkown internal scanner error",
|
||||
"Error: could not match input",
|
||||
"Error: pushback value was too large"
|
||||
};
|
||||
|
||||
/**
|
||||
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
|
||||
*/
|
||||
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
|
||||
|
||||
private static final String ZZ_ATTRIBUTE_PACKED_0 =
|
||||
"\5\0\2\1\1\11\2\1\1\0\2\1\1\0\2\1"+
|
||||
"\1\11\5\1\3\0\1\1\7\0\2\11\1\0\1\11"+
|
||||
"\1\0\2\11\3\0\1\1\2\0\1\11\1\0\3\11"+
|
||||
"\2\0\3\11\4\0\1\11";
|
||||
|
||||
private static int [] zzUnpackAttribute() {
|
||||
int [] result = new int[61];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackAttribute(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/** the input device */
|
||||
private java.io.Reader zzReader;
|
||||
|
||||
/** the current state of the DFA */
|
||||
private int zzState;
|
||||
|
||||
/** the current lexical state */
|
||||
private int zzLexicalState = YYINITIAL;
|
||||
|
||||
/** this buffer contains the current text to be matched and is
|
||||
the source of the yytext() string */
|
||||
private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
|
||||
|
||||
/** the textposition at the last accepting state */
|
||||
private int zzMarkedPos;
|
||||
|
||||
/** the current text position in the buffer */
|
||||
private int zzCurrentPos;
|
||||
|
||||
/** startRead marks the beginning of the yytext() string in the buffer */
|
||||
private int zzStartRead;
|
||||
|
||||
/** endRead marks the last character in the buffer, that has been read
|
||||
from input */
|
||||
private int zzEndRead;
|
||||
|
||||
/** number of newlines encountered up to the start of the matched text */
|
||||
private int yyline;
|
||||
|
||||
/** the number of characters up to the start of the matched text */
|
||||
private int yychar;
|
||||
|
||||
/**
|
||||
* the number of characters from the last newline up to the start of the
|
||||
* matched text
|
||||
*/
|
||||
private int yycolumn;
|
||||
|
||||
/**
|
||||
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
|
||||
*/
|
||||
private boolean zzAtBOL = true;
|
||||
|
||||
/** zzAtEOF == true <=> the scanner is at the EOF */
|
||||
private boolean zzAtEOF;
|
||||
|
||||
/** denotes if the user-EOF-code has already been executed */
|
||||
private boolean zzEOFDone;
|
||||
|
||||
/**
|
||||
* The number of occupied positions in zzBuffer beyond zzEndRead.
|
||||
* When a lead/high surrogate has been read from the input stream
|
||||
* into the final zzBuffer position, this will have a value of 1;
|
||||
* otherwise, it will have a value of 0.
|
||||
*/
|
||||
private int zzFinalHighSurrogate = 0;
|
||||
|
||||
/* user code: */
|
||||
public XmlLexer() {
|
||||
super();
|
||||
}
|
||||
|
||||
private static final byte TAG_OPEN = 1;
|
||||
private static final byte TAG_CLOSE = -1;
|
||||
|
||||
private static final byte INSTR_OPEN = 2;
|
||||
private static final byte INSTR_CLOSE = -2;
|
||||
|
||||
private static final byte CDATA_OPEN = 3;
|
||||
private static final byte CDATA_CLOSE = -3;
|
||||
|
||||
private static final byte COMMENT_OPEN = 4;
|
||||
private static final byte COMMENT_CLOSE = -4;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new scanner
|
||||
*
|
||||
* @param in the java.io.Reader to read input from.
|
||||
*/
|
||||
public XmlLexer(java.io.Reader in) {
|
||||
this.zzReader = in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unpacks the compressed character translation table.
|
||||
*
|
||||
* @param packed the packed character translation table
|
||||
* @return the unpacked character translation table
|
||||
*/
|
||||
private static char [] zzUnpackCMap(String packed) {
|
||||
char [] map = new char[0x110000];
|
||||
int i = 0; /* index in packed string */
|
||||
int j = 0; /* index in unpacked array */
|
||||
while (i < 376) {
|
||||
int count = packed.charAt(i++);
|
||||
char value = packed.charAt(i++);
|
||||
do map[j++] = value; while (--count > 0);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refills the input buffer.
|
||||
*
|
||||
* @return <code>false</code>, iff there was new input.
|
||||
*
|
||||
* @exception java.io.IOException if any I/O-Error occurs
|
||||
*/
|
||||
private boolean zzRefill() throws java.io.IOException {
|
||||
|
||||
/* first: make room (if you can) */
|
||||
if (zzStartRead > 0) {
|
||||
zzEndRead += zzFinalHighSurrogate;
|
||||
zzFinalHighSurrogate = 0;
|
||||
System.arraycopy(zzBuffer, zzStartRead,
|
||||
zzBuffer, 0,
|
||||
zzEndRead-zzStartRead);
|
||||
|
||||
/* translate stored positions */
|
||||
zzEndRead-= zzStartRead;
|
||||
zzCurrentPos-= zzStartRead;
|
||||
zzMarkedPos-= zzStartRead;
|
||||
zzStartRead = 0;
|
||||
}
|
||||
|
||||
/* is the buffer big enough? */
|
||||
if (zzCurrentPos >= zzBuffer.length - zzFinalHighSurrogate) {
|
||||
/* if not: blow it up */
|
||||
char newBuffer[] = new char[zzBuffer.length*2];
|
||||
System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
|
||||
zzBuffer = newBuffer;
|
||||
zzEndRead += zzFinalHighSurrogate;
|
||||
zzFinalHighSurrogate = 0;
|
||||
}
|
||||
|
||||
/* fill the buffer with new input */
|
||||
int requested = zzBuffer.length - zzEndRead;
|
||||
int totalRead = 0;
|
||||
while (totalRead < requested) {
|
||||
int numRead = zzReader.read(zzBuffer, zzEndRead + totalRead, requested - totalRead);
|
||||
if (numRead == -1) {
|
||||
break;
|
||||
}
|
||||
totalRead += numRead;
|
||||
}
|
||||
|
||||
if (totalRead > 0) {
|
||||
zzEndRead += totalRead;
|
||||
if (totalRead == requested) { /* possibly more input available */
|
||||
if (Character.isHighSurrogate(zzBuffer[zzEndRead - 1])) {
|
||||
--zzEndRead;
|
||||
zzFinalHighSurrogate = 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// totalRead = 0: End of stream
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the input stream.
|
||||
*/
|
||||
public final void yyclose() throws java.io.IOException {
|
||||
zzAtEOF = true; /* indicate end of file */
|
||||
zzEndRead = zzStartRead; /* invalidate buffer */
|
||||
|
||||
if (zzReader != null)
|
||||
zzReader.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets the scanner to read from a new input stream.
|
||||
* Does not close the old reader.
|
||||
*
|
||||
* All internal variables are reset, the old input stream
|
||||
* <b>cannot</b> be reused (internal buffer is discarded and lost).
|
||||
* Lexical state is set to <tt>ZZ_INITIAL</tt>.
|
||||
*
|
||||
* Internal scan buffer is resized down to its initial length, if it has grown.
|
||||
*
|
||||
* @param reader the new input stream
|
||||
*/
|
||||
public final void yyreset(java.io.Reader reader) {
|
||||
zzReader = reader;
|
||||
zzAtBOL = true;
|
||||
zzAtEOF = false;
|
||||
zzEOFDone = false;
|
||||
zzEndRead = zzStartRead = 0;
|
||||
zzCurrentPos = zzMarkedPos = 0;
|
||||
zzFinalHighSurrogate = 0;
|
||||
yyline = yychar = yycolumn = 0;
|
||||
zzLexicalState = YYINITIAL;
|
||||
if (zzBuffer.length > ZZ_BUFFERSIZE)
|
||||
zzBuffer = new char[ZZ_BUFFERSIZE];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current lexical state.
|
||||
*/
|
||||
public final int yystate() {
|
||||
return zzLexicalState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enters a new lexical state
|
||||
*
|
||||
* @param newState the new lexical state
|
||||
*/
|
||||
public final void yybegin(int newState) {
|
||||
zzLexicalState = newState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the text matched by the current regular expression.
|
||||
*/
|
||||
public final String yytext() {
|
||||
return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the character at position <tt>pos</tt> from the
|
||||
* matched text.
|
||||
*
|
||||
* It is equivalent to yytext().charAt(pos), but faster
|
||||
*
|
||||
* @param pos the position of the character to fetch.
|
||||
* A value from 0 to yylength()-1.
|
||||
*
|
||||
* @return the character at position pos
|
||||
*/
|
||||
public final char yycharat(int pos) {
|
||||
return zzBuffer[zzStartRead+pos];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the length of the matched text region.
|
||||
*/
|
||||
public final int yylength() {
|
||||
return zzMarkedPos-zzStartRead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reports an error that occured while scanning.
|
||||
*
|
||||
* In a wellformed scanner (no or only correct usage of
|
||||
* yypushback(int) and a match-all fallback rule) this method
|
||||
* will only be called with things that "Can't Possibly Happen".
|
||||
* If this method is called, something is seriously wrong
|
||||
* (e.g. a JFlex bug producing a faulty scanner etc.).
|
||||
*
|
||||
* Usual syntax/scanner level error handling should be done
|
||||
* in error fallback rules.
|
||||
*
|
||||
* @param errorCode the code of the errormessage to display
|
||||
*/
|
||||
private void zzScanError(int errorCode) {
|
||||
String message;
|
||||
try {
|
||||
message = ZZ_ERROR_MSG[errorCode];
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pushes the specified amount of characters back into the input stream.
|
||||
*
|
||||
* They will be read again by then next call of the scanning method
|
||||
*
|
||||
* @param number the number of characters to be read again.
|
||||
* This number must not be greater than yylength()!
|
||||
*/
|
||||
public void yypushback(int number) {
|
||||
if ( number > yylength() )
|
||||
zzScanError(ZZ_PUSHBACK_2BIG);
|
||||
|
||||
zzMarkedPos -= number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resumes scanning until the next regular expression is matched,
|
||||
* the end of input is encountered or an I/O-Error occurs.
|
||||
*
|
||||
* @return the next token
|
||||
* @exception java.io.IOException if any I/O-Error occurs
|
||||
*/
|
||||
public XmlParsedSymbol yylex() throws java.io.IOException, XmlException {
|
||||
int zzInput;
|
||||
int zzAction;
|
||||
|
||||
// cached fields:
|
||||
int zzCurrentPosL;
|
||||
int zzMarkedPosL;
|
||||
int zzEndReadL = zzEndRead;
|
||||
char [] zzBufferL = zzBuffer;
|
||||
char [] zzCMapL = ZZ_CMAP;
|
||||
|
||||
int [] zzTransL = ZZ_TRANS;
|
||||
int [] zzRowMapL = ZZ_ROWMAP;
|
||||
int [] zzAttrL = ZZ_ATTRIBUTE;
|
||||
|
||||
while (true) {
|
||||
zzMarkedPosL = zzMarkedPos;
|
||||
|
||||
yychar+= zzMarkedPosL-zzStartRead;
|
||||
|
||||
zzAction = -1;
|
||||
|
||||
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
|
||||
|
||||
zzState = ZZ_LEXSTATE[zzLexicalState];
|
||||
|
||||
// set up zzAction for empty match case:
|
||||
int zzAttributes = zzAttrL[zzState];
|
||||
if ( (zzAttributes & 1) == 1 ) {
|
||||
zzAction = zzState;
|
||||
}
|
||||
|
||||
|
||||
zzForAction: {
|
||||
while (true) {
|
||||
|
||||
if (zzCurrentPosL < zzEndReadL) {
|
||||
zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL);
|
||||
zzCurrentPosL += Character.charCount(zzInput);
|
||||
}
|
||||
else if (zzAtEOF) {
|
||||
zzInput = YYEOF;
|
||||
break zzForAction;
|
||||
}
|
||||
else {
|
||||
// store back cached positions
|
||||
zzCurrentPos = zzCurrentPosL;
|
||||
zzMarkedPos = zzMarkedPosL;
|
||||
boolean eof = zzRefill();
|
||||
// get translated positions and possibly new buffer
|
||||
zzCurrentPosL = zzCurrentPos;
|
||||
zzMarkedPosL = zzMarkedPos;
|
||||
zzBufferL = zzBuffer;
|
||||
zzEndReadL = zzEndRead;
|
||||
if (eof) {
|
||||
zzInput = YYEOF;
|
||||
break zzForAction;
|
||||
}
|
||||
else {
|
||||
zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL);
|
||||
zzCurrentPosL += Character.charCount(zzInput);
|
||||
}
|
||||
}
|
||||
int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
|
||||
if (zzNext == -1) break zzForAction;
|
||||
zzState = zzNext;
|
||||
|
||||
zzAttributes = zzAttrL[zzState];
|
||||
if ( (zzAttributes & 1) == 1 ) {
|
||||
zzAction = zzState;
|
||||
zzMarkedPosL = zzCurrentPosL;
|
||||
if ( (zzAttributes & 8) == 8 ) break zzForAction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// store back cached position
|
||||
zzMarkedPos = zzMarkedPosL;
|
||||
|
||||
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
|
||||
case 1:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.CHARACTER, yytext(), yytext(), yychar);
|
||||
}
|
||||
case 20: break;
|
||||
case 2:
|
||||
{ throw new XmlException("Incorrect text: \"" + yytext() + "\"");
|
||||
}
|
||||
case 21: break;
|
||||
case 3:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.WHITESPACE, yytext(), yychar);
|
||||
}
|
||||
case 22: break;
|
||||
case 4:
|
||||
{ yybegin(YYINITIAL);
|
||||
return new XmlParsedSymbol(XmlSymbolType.TAG_OPEN_END, yytext(), yychar);
|
||||
}
|
||||
case 23: break;
|
||||
case 5:
|
||||
{ yybegin(TAG);
|
||||
return new XmlParsedSymbol(XmlSymbolType.TAG_OPEN, yytext().substring(1), yytext(), yychar);
|
||||
}
|
||||
case 24: break;
|
||||
case 6:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.ATTRIBUTE, yytext().substring(0, yytext().length() - 1).trim(), yytext(), yychar);
|
||||
}
|
||||
case 25: break;
|
||||
case 7:
|
||||
{ yybegin(YYINITIAL);
|
||||
return new XmlParsedSymbol(XmlSymbolType.TAG_CLOSE, yytext(), yychar);
|
||||
}
|
||||
case 26: break;
|
||||
case 8:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.ATTRIBUTE_VALUE, yytext().substring(1, yytext().length() - 1), yytext(), yychar);
|
||||
}
|
||||
case 27: break;
|
||||
case 9:
|
||||
{ yybegin(YYINITIAL);
|
||||
return new XmlParsedSymbol(XmlSymbolType.INSTR_CLOSE, yytext(), yychar);
|
||||
}
|
||||
case 28: break;
|
||||
case 10:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.ENTITY, yytext().substring(1, yytext().length() - 1), yytext(), yychar);
|
||||
}
|
||||
case 29: break;
|
||||
case 11:
|
||||
{ yybegin(INSTR);
|
||||
return new XmlParsedSymbol(XmlSymbolType.INSTR_OPEN, yytext(), yychar);
|
||||
}
|
||||
case 30: break;
|
||||
case 12:
|
||||
{ yybegin(YYINITIAL);
|
||||
return new XmlParsedSymbol(XmlSymbolType.COMMENT_CLOSE, yytext(), yychar);
|
||||
}
|
||||
case 31: break;
|
||||
case 13:
|
||||
{ yybegin(YYINITIAL);
|
||||
return new XmlParsedSymbol(XmlSymbolType.CDATA_CLOSE, yytext(), yychar);
|
||||
}
|
||||
case 32: break;
|
||||
case 14:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.ENTITY_NUMERIC, Integer.parseInt(yytext().substring(1, yytext().length() - 1)), yytext(), yychar);
|
||||
}
|
||||
case 33: break;
|
||||
case 15:
|
||||
{ yybegin(COMMENT);
|
||||
return new XmlParsedSymbol(XmlSymbolType.COMMENT_OPEN, yytext(), yychar);
|
||||
}
|
||||
case 34: break;
|
||||
case 16:
|
||||
{ return new XmlParsedSymbol(XmlSymbolType.TAG_CLOSE, yytext().substring(2, yytext().length() - 1), yytext(), yychar);
|
||||
}
|
||||
case 35: break;
|
||||
case 17:
|
||||
{ yypushback(3);
|
||||
return new XmlParsedSymbol(XmlSymbolType.COMMENT, yytext().substring(yytext().length() - 3), yytext().substring(yytext().length() - 3), yychar);
|
||||
}
|
||||
case 36: break;
|
||||
case 18:
|
||||
{ yypushback(3);
|
||||
return new XmlParsedSymbol(XmlSymbolType.CDATA, yytext().substring(yytext().length() - 3), yytext().substring(yytext().length() - 3), yychar);
|
||||
}
|
||||
case 37: break;
|
||||
case 19:
|
||||
{ yybegin(CDATA);
|
||||
return new XmlParsedSymbol(XmlSymbolType.CDATA_OPEN, yytext(), yychar);
|
||||
}
|
||||
case 38: break;
|
||||
default:
|
||||
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
|
||||
zzAtEOF = true;
|
||||
switch (zzLexicalState) {
|
||||
case YYINITIAL: {
|
||||
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
|
||||
}
|
||||
case 62: break;
|
||||
case COMMENT: {
|
||||
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
|
||||
}
|
||||
case 63: break;
|
||||
case CDATA: {
|
||||
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
|
||||
}
|
||||
case 64: break;
|
||||
case TAG: {
|
||||
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
|
||||
}
|
||||
case 65: break;
|
||||
case INSTR: {
|
||||
return new XmlParsedSymbol(XmlSymbolType.EOF, "", -1);
|
||||
}
|
||||
case 66: break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
zzScanError(ZZ_NO_MATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2025 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.text.xml;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class XmlParsedSymbol {
|
||||
public Object value;
|
||||
|
||||
public XmlSymbolType type;
|
||||
|
||||
public String rawText;
|
||||
|
||||
public int position;
|
||||
|
||||
public XmlParsedSymbol(XmlSymbolType type, String rawText, int position) {
|
||||
this.type = type;
|
||||
this.value = "";
|
||||
this.rawText = rawText;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public XmlParsedSymbol(XmlSymbolType type, Object value, String rawText, int position) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.rawText = rawText;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.toString() + " " + value.toString();
|
||||
}
|
||||
|
||||
public boolean isType(XmlSymbolType... types) {
|
||||
for (XmlSymbolType t : types) {
|
||||
if (type == t) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2025 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.text.xml;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum XmlSymbolType {
|
||||
ENTITY,
|
||||
ENTITY_NUMERIC,
|
||||
INSTR_OPEN,
|
||||
TAG_OPEN,
|
||||
TAG_OPEN_END,
|
||||
TAG_CLOSE,
|
||||
COMMENT_OPEN,
|
||||
COMMENT,
|
||||
COMMENT_CLOSE,
|
||||
CDATA_OPEN,
|
||||
CDATA,
|
||||
CDATA_CLOSE,
|
||||
CHARACTER,
|
||||
ATTRIBUTE,
|
||||
ATTRIBUTE_VALUE,
|
||||
INSTR_CLOSE,
|
||||
WHITESPACE,
|
||||
EOF
|
||||
}
|
||||
@@ -1231,28 +1231,30 @@ public class Timeline {
|
||||
}
|
||||
|
||||
if (drawable instanceof TextTag) {
|
||||
if (renderContext.cursorPosition != null && renderContext.enableTexts) {
|
||||
TextTag textTag = (TextTag) drawable;
|
||||
Matrix textMatrix = new Matrix(textTag.getTextMatrix());
|
||||
if (drawable == renderContext.selectionText) {
|
||||
renderContext.selectionAbsMatrix = absMat.concatenate(textMatrix);
|
||||
}
|
||||
if (renderContext.enableTexts) {
|
||||
int dx = (int) (viewRect.xMin * unzoom);
|
||||
int dy = (int) (viewRect.yMin * unzoom);
|
||||
Point cursorPositionInView = new Point((int) Math.round(renderContext.cursorPosition.x * unzoom) - dx, (int) Math.round(renderContext.cursorPosition.y * unzoom) - dy);
|
||||
Point cursorPositionInView = renderContext.cursorPosition == null ? new Point(0, 0) : new Point((int) Math.round(renderContext.cursorPosition.x * unzoom) - dx, (int) Math.round(renderContext.cursorPosition.y * unzoom) - dy);
|
||||
|
||||
Shape textShape = ((TextTag) drawable).getOutline(true, 0, 0, 0, renderContext, absMat, true, viewRect, unzoom);
|
||||
|
||||
TextTag textTag = (TextTag) drawable;
|
||||
|
||||
|
||||
if (textShape.contains(cursorPositionInView)) {
|
||||
renderContext.mouseOverText = textTag;
|
||||
renderContext.mouseOverTextAbsMatrix = absMat;
|
||||
}
|
||||
|
||||
if (textShape.contains(cursorPositionInView) || (drawable == renderContext.selectionText && renderContext.mouseButton == 1)) {
|
||||
Rectangle textBounds = textShape.getBounds();
|
||||
List<TEXTRECORD> textRecords = new ArrayList<>();
|
||||
Matrix textMatrix = new Matrix();
|
||||
if (textTag instanceof StaticTextTag) {
|
||||
textRecords = ((StaticTextTag) textTag).textRecords;
|
||||
MATRIX tm = ((StaticTextTag) textTag).textMatrix;
|
||||
if (tm != null) {
|
||||
textMatrix = new Matrix(tm);
|
||||
}
|
||||
textRecords = ((StaticTextTag) textTag).textRecords;
|
||||
}
|
||||
if (textTag instanceof DefineEditTextTag) {
|
||||
textRecords = ((DefineEditTextTag) textTag).getTextRecords(textTag.getSwf());
|
||||
@@ -1264,6 +1266,8 @@ public class Timeline {
|
||||
int closestPos = -1;
|
||||
double closestDistance = Double.MAX_VALUE;
|
||||
Point cursorPosNoTrans = absMat.concatenate(textMatrix).inverse().transform(cursorPositionInView);
|
||||
|
||||
pos = 0;
|
||||
for (RECT gp : glyphPositions) {
|
||||
/*Rectangle2D r = new Rectangle2D.Double(
|
||||
textBounds.x + gp.Xmin * unzoom,
|
||||
@@ -1301,6 +1305,12 @@ public class Timeline {
|
||||
break;
|
||||
}
|
||||
|
||||
/*if (drawable == renderContext.selectionText && pos == renderContext.selectionStart) {
|
||||
closestPos = pos;
|
||||
closestDistance = 0;
|
||||
break;
|
||||
}*/
|
||||
|
||||
if (cursorPosNoTrans.y >= r.getY() && cursorPosNoTrans.y <= r.getMaxY()) {
|
||||
double tx = Math.max(r.getMinX() - cursorPosNoTrans.getX(), 0);
|
||||
tx = Math.max(tx, cursorPosNoTrans.getX() - r.getMaxX());
|
||||
@@ -1331,12 +1341,12 @@ public class Timeline {
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (closestPos == -1) {
|
||||
if (closestPos == -1 && renderContext.mouseButton == 1) {
|
||||
if (!glyphPositions.isEmpty()) {
|
||||
RECT gp = glyphPositions.get(0);
|
||||
Rectangle2D r = new Rectangle2D.Double(
|
||||
gp.Xmin * unzoom,
|
||||
gp.Ymin * unzoom,
|
||||
gp.Xmin,
|
||||
gp.Ymin,
|
||||
gp.Xmax - gp.Xmin,
|
||||
gp.Ymax - gp.Ymin
|
||||
);
|
||||
@@ -1346,8 +1356,8 @@ public class Timeline {
|
||||
|
||||
gp = glyphPositions.get(glyphPositions.size() - 1);
|
||||
r = new Rectangle2D.Double(
|
||||
gp.Xmin * unzoom,
|
||||
gp.Ymin * unzoom,
|
||||
gp.Xmin,
|
||||
gp.Ymin,
|
||||
gp.Xmax - gp.Xmin,
|
||||
gp.Ymax - gp.Ymin
|
||||
);
|
||||
@@ -1360,8 +1370,8 @@ public class Timeline {
|
||||
if (closestPos > -1) {
|
||||
RECT gp = glyphPositions.get(closestPos);
|
||||
Rectangle2D r = new Rectangle2D.Double(
|
||||
gp.Xmin * unzoom,
|
||||
gp.Ymin * unzoom,
|
||||
gp.Xmin,
|
||||
gp.Ymin,
|
||||
gp.Xmax - gp.Xmin,
|
||||
gp.Ymax - gp.Ymin
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user