diff --git a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java
index c8b1a3e846..2bc0bfde5b 100644
--- a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java
+++ b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java
@@ -51,6 +51,7 @@ import net.runelite.api.widgets.WidgetTextAlignment;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseListener;
+import net.runelite.client.util.Text;
@Slf4j
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
@@ -233,9 +234,9 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
{
Widget container = chatboxPanelManager.getContainerWidget();
- String lt = value.substring(0, this.cursor);
- String mt = value.substring(this.cursor, this.cursorEnd);
- String rt = value.substring(this.cursorEnd);
+ String lt = Text.escapeJagex(value.substring(0, this.cursor));
+ String mt = Text.escapeJagex(value.substring(this.cursor, this.cursorEnd));
+ String rt = Text.escapeJagex(value.substring(this.cursorEnd));
Widget leftText = container.createChild(-1, WidgetType.TEXT);
Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
@@ -332,9 +333,9 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
// `i` is used to track max execution time incase there is a font with ligature width data that causes this to fail
for (int i = tsValue.length(); i >= 0 && charIndex >= 0 && charIndex <= tsValue.length(); i--)
{
- int lcx = charIndex > 0 ? font.getTextWidth(tsValue.substring(0, charIndex - 1)) : 0;
- int mcx = font.getTextWidth(tsValue.substring(0, charIndex));
- int rcx = charIndex + 1 <= tsValue.length() ? font.getTextWidth(tsValue.substring(0, charIndex + 1)) : mcx;
+ int lcx = charIndex > 0 ? font.getTextWidth(Text.escapeJagex(tsValue.substring(0, charIndex - 1))) : 0;
+ int mcx = font.getTextWidth(Text.escapeJagex(tsValue.substring(0, charIndex)));
+ int rcx = charIndex + 1 <= tsValue.length() ? font.getTextWidth(Text.escapeJagex(tsValue.substring(0, charIndex + 1))) : mcx;
int leftBound = (lcx + mcx) / 2;
int rightBound = (mcx + rcx) / 2;
diff --git a/runelite-client/src/main/java/net/runelite/client/util/Text.java b/runelite-client/src/main/java/net/runelite/client/util/Text.java
index 72be89f3b4..9f73e947a6 100644
--- a/runelite-client/src/main/java/net/runelite/client/util/Text.java
+++ b/runelite-client/src/main/java/net/runelite/client/util/Text.java
@@ -36,10 +36,10 @@ public class Text
private static final Pattern TAG_REGEXP = Pattern.compile("<[^>]*>");
/**
- * Removes all tags from the given `str`.
+ * Removes all tags from the given string.
*
* @param str The string to remove tags from.
- * @return The given `str` with all tags removed from it.
+ * @return The given string with all tags removed from it.
*/
public static String removeTags(String str)
{
@@ -70,7 +70,7 @@ public class Text
}
/**
- * In addition to removing all tags, replaces all
delimited text with spaces and all multiple continuous
+ * In addition to removing all tags, replaces all <br> delimited text with spaces and all multiple continuous
* spaces with single space
*
* @param str The string to sanitize
@@ -83,4 +83,35 @@ public class Text
.replaceAll("
", " ")
.replaceAll("[ ]+", " "));
}
+
+ /**
+ * Escapes a string for widgets, replacing < and > with their escaped counterparts
+ */
+ public static String escapeJagex(String str)
+ {
+ StringBuilder out = new StringBuilder(str.length());
+
+ for (int i = 0; i < str.length(); i++)
+ {
+ char c = str.charAt(i);
+ if (c == '<')
+ {
+ out.append("");
+ }
+ else if (c == '>')
+ {
+ out.append("");
+ }
+ else if (c == '\n')
+ {
+ out.append("
");
+ }
+ else if (c != '\r')
+ {
+ out.append(c);
+ }
+ }
+
+ return out.toString();
+ }
}
diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/ScriptVMMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/ScriptVMMixin.java
index 7293f9daa1..29f632576a 100644
--- a/runelite-mixins/src/main/java/net/runelite/mixins/ScriptVMMixin.java
+++ b/runelite-mixins/src/main/java/net/runelite/mixins/ScriptVMMixin.java
@@ -119,7 +119,14 @@ public abstract class ScriptVMMixin implements RSClient
Object[] arguments = event.getArguments();
if (arguments != null && arguments.length > 0 && arguments[0] instanceof JavaScriptCallback)
{
- ((JavaScriptCallback) arguments[0]).run(event);
+ try
+ {
+ ((JavaScriptCallback) arguments[0]).run(event);
+ }
+ catch (Exception e)
+ {
+ client.getLogger().error("Error in JavaScriptCallback", e);
+ }
return;
}