diff --git a/src/main/java/net/rptools/maptool/client/functions/ShapeFunctions.java b/src/main/java/net/rptools/maptool/client/functions/ShapeFunctions.java index c326fbf4e3..ada59442c6 100644 --- a/src/main/java/net/rptools/maptool/client/functions/ShapeFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/ShapeFunctions.java @@ -20,8 +20,6 @@ import com.google.gson.JsonObject; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.functions.json.JSONMacroFunctions; -import net.rptools.maptool.client.swing.MapToolEventQueue; -import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer; import net.rptools.maptool.language.I18N; import net.rptools.maptool.model.GUID; import net.rptools.maptool.model.Zone; @@ -214,9 +212,8 @@ private Object combinePaths( private Object copyShape( Parser parser, VariableResolver resolver, String functionName, List parameters) throws ParserException { - /* - copy name, shape name - */ + // copy name, shape name + FunctionUtil.checkNumberParam(functionName, parameters, 2, 2); String shapeName = FunctionUtil.paramAsString(functionName, parameters, 1, false); if (!CACHED_SHAPES.containsKey(shapeName)) { @@ -237,35 +234,106 @@ private Object copyShape( private Object createShape( Parser parser, VariableResolver resolver, String functionName, List parameters) throws ParserException { - /* - name, layer, anti-aliasing, type, shape arguments, transforms - */ - FunctionUtil.checkNumberParam(functionName, parameters, 5, 6); + FunctionUtil.checkNumberParam(functionName, parameters, 5, 8); + int numParam = parameters.size(); + int transformIndex = -1; + + if (numParam == 8) { + transformIndex = 6; + } else if (numParam == 7) { + // one arg is a delimiter + if (parameters.get(5) instanceof JsonElement) { + transformIndex = 5; + } else if (parameters.get(6) instanceof JsonElement) { + transformIndex = 6; + } else if (((String) parameters.get(5)).equalsIgnoreCase("json")) { + transformIndex = 6; + } else if (((String) parameters.get(6)).equalsIgnoreCase("json")) { + transformIndex = 5; + } else if (((String) parameters.get(5)).length() > 6) { // too long for a delimiter + transformIndex = 5; + } else if (((String) parameters.get(6)).length() > 6) { // too long for a delimiter + transformIndex = 6; + } + } else if (numParam == 6) { + // arg index 5 MAY be a delimiter + if (parameters.get(5) instanceof JsonElement) { + transformIndex = 5; + } else if (((String) parameters.get(5)).equalsIgnoreCase("json")) { // is a delimiter + // no change + } else if (((String) parameters.get(5)).length() > 6) { // too long for a delimiter + transformIndex = 5; + } + } + return createShape(parser, resolver, functionName, parameters, transformIndex); + } + + private Object createShape( + Parser parser, + VariableResolver resolver, + String functionName, + List parameters, + int transformIndex) + throws ParserException { + // 0. name, 1. layer, 2. anti-aliasing, 3. type, 4. shape arguments, [5. delimiter1], [6. + // transforms], [7. delimiter2] + Object[] leadParams = getLeadParameters(functionName, parameters); GUID guid = (GUID) leadParams[0]; String name = leadParams[1].toString(); Zone.Layer layer = (Zone.Layer) leadParams[2]; boolean aa = (boolean) leadParams[3]; - String shapeType = FunctionUtil.paramAsString(functionName, parameters, 3, true).toLowerCase(); - Shape shape = - switch (shapeType) { - case "arc" -> arc(functionName, parameters); - case "cubiccurve" -> cubicCurve(functionName, parameters); - case "ellipse" -> ellipse(functionName, parameters); - case "line" -> line(functionName, parameters); - case "path" -> path(functionName, parameters); - case "polygon" -> polygon(functionName, parameters); - case "quadcurve" -> quadCurve(functionName, parameters); - case "rectangle" -> rectangle(functionName, parameters); - case "roundrectangle" -> roundRectangle(functionName, parameters); - case "svgpath" -> svgPath(functionName, parameters); - default -> throw new ParserException( - I18N.getText(UNSUPPORTED_OPERATION, functionName, 3, shapeType)); - }; - if (parameters.size() > 5) { - shape = transform(shape, functionName, parameters, 5); + Shape shape; + String delimiter = + (transformIndex == -1 && parameters.size() == 6) || transformIndex == 6 + ? FunctionUtil.paramAsString(functionName, parameters, 5, false) + : ";"; + if (shapeType.equalsIgnoreCase("svgpath")) { + shape = svgPath(functionName, FunctionUtil.paramAsString(functionName, parameters, 4, true)); + } else if (shapeType.equalsIgnoreCase("path")) { + JsonArray pathArray = new JsonArray(); + if (delimiter.equalsIgnoreCase("json")) { + pathArray = FunctionUtil.paramConvertedToJson(functionName, parameters, 4).getAsJsonArray(); + } else { + String pathString = FunctionUtil.paramAsString(functionName, parameters, 4, true); + pathString = pathString.replaceAll("\\s", ""); + if (pathString.contains("[")) { + pathArray = FunctionUtil.paramAsJsonArray(functionName, parameters, 4); + } else { + for (String s : pathString.split(delimiter)) { + pathArray.add(s); + } + } + } + shape = path(functionName, pathArray); + } else { + JsonObject shapeParams = + FunctionUtil.jsonWithLowerCaseKeys( + FunctionUtil.paramFromStrPropOrJsonAsJsonObject( + functionName, parameters, 4, delimiter)); + shape = + switch (shapeType) { + case "arc" -> arc(functionName, shapeParams); + case "cubiccurve" -> cubicCurve(functionName, shapeParams); + case "ellipse" -> ellipse(functionName, shapeParams); + case "line" -> line(functionName, shapeParams); + case "polygon" -> polygon(functionName, shapeParams); + case "quadcurve" -> quadCurve(functionName, shapeParams); + case "rectangle" -> rectangle(functionName, shapeParams); + case "roundrectangle" -> roundRectangle(functionName, shapeParams); + default -> throw new ParserException( + I18N.getText(UNSUPPORTED_OPERATION, functionName, 3, shapeType)); + }; + } + if (transformIndex != -1) { + String delimiter2 = ","; + if (transformIndex == parameters.size() - 2) { + delimiter2 = + FunctionUtil.paramAsString(functionName, parameters, transformIndex + 1, false); + } + shape = transform(shape, functionName, parameters, transformIndex, delimiter2); } ShapeDrawable sd = new ShapeDrawable(guid, shape, aa); sd.setName(name); @@ -291,10 +359,9 @@ private boolean deleteShape( private Object drawShape( Parser parser, VariableResolver resolver, String functionName, List parameters) throws ParserException { - /* - name, map name - */ - FunctionUtil.checkNumberParam(functionName, parameters, 2, 3); + // name, map name, pen, delimiter + + FunctionUtil.checkNumberParam(functionName, parameters, 2, 4); String shapeName = FunctionUtil.paramAsString(functionName, parameters, 0, false); String mapName = FunctionUtil.paramAsString(functionName, parameters, 1, true); if (!CACHED_SHAPES.containsKey(shapeName)) { @@ -302,76 +369,74 @@ private Object drawShape( } ShapeDrawable shapeDrawable = CACHED_SHAPES.get(shapeName); Rectangle bounds = shapeDrawable.getBounds(); - if (bounds.width > 0 - && bounds.height > 0 - && bounds.width < 10000 - && bounds.height < 10000 - && (double) Math.min(bounds.width, bounds.height) / Math.max(bounds.width, bounds.height) - > 0.005) { - Pen pen = new Pen(Pen.DEFAULT); - if (parameters.size() > 2) { - JsonObject penObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 2)); - - if (penObject.keySet().contains("foreground")) { - String fg = penObject.get("foreground").getAsString(); - if (fg.equalsIgnoreCase("transparent") || fg.equalsIgnoreCase("")) { - pen.setForegroundMode(Pen.MODE_TRANSPARENT); - } else { - pen.setForegroundMode(Pen.MODE_SOLID); - pen.setPaint(FunctionUtil.getPaintFromString(fg)); - } - } - if (penObject.keySet().contains("background")) { - String bg = penObject.get("background").getAsString(); - if (bg.equalsIgnoreCase("transparent") || bg.equalsIgnoreCase("")) { - pen.setBackgroundMode(Pen.MODE_TRANSPARENT); - } else { - pen.setBackgroundMode(Pen.MODE_SOLID); - pen.setBackgroundPaint(FunctionUtil.getPaintFromString(bg)); - } - } - if (penObject.keySet().contains("width")) { - pen.setThickness(penObject.get("width").getAsFloat()); - } - if (penObject.keySet().contains("squarecap")) { - pen.setSquareCap(penObject.get("squarecap").getAsBoolean()); + + // Sanity checks + if ((bounds.width == 0 && bounds.height == 0) + || bounds.width > 50000 + || bounds.height > 50000) { + return false; + } + + Pen pen = new Pen(Pen.DEFAULT); + if (parameters.size() > 2) { + String delimiter = ";"; + if (parameters.size() > 3) { + delimiter = FunctionUtil.paramAsString(functionName, parameters, 3, false); + } + JsonObject penObject = + FunctionUtil.jsonWithLowerCaseKeys( + FunctionUtil.paramFromStrPropOrJsonAsJsonObject( + functionName, parameters, 2, delimiter)); + + if (penObject.keySet().contains("foreground")) { + String fg = penObject.get("foreground").getAsString(); + if (fg.equalsIgnoreCase("transparent") || fg.equalsIgnoreCase("")) { + pen.setForegroundMode(Pen.MODE_TRANSPARENT); + } else { + pen.setForegroundMode(Pen.MODE_SOLID); + pen.setPaint(FunctionUtil.getPaintFromString(fg)); } - if (penObject.keySet().contains("opacity")) { - float opacity = penObject.get("opacity").getAsFloat(); - if (opacity <= 1f) { - pen.setOpacity(opacity); - } else if (opacity <= 255f) { - pen.setOpacity(opacity / 255f); - } + } + if (penObject.keySet().contains("background")) { + String bg = penObject.get("background").getAsString(); + if (bg.equalsIgnoreCase("transparent") || bg.equalsIgnoreCase("")) { + pen.setBackgroundMode(Pen.MODE_TRANSPARENT); + } else { + pen.setBackgroundMode(Pen.MODE_SOLID); + pen.setBackgroundPaint(FunctionUtil.getPaintFromString(bg)); } - if (penObject.keySet().contains("eraser")) { - pen.setEraser(penObject.get("eraser").getAsBoolean()); + } + if (penObject.keySet().contains("width")) { + pen.setThickness(penObject.get("width").getAsFloat()); + } + if (penObject.keySet().contains("squarecap")) { + pen.setSquareCap(penObject.get("squarecap").getAsBoolean()); + } + if (penObject.keySet().contains("opacity")) { + float opacity = penObject.get("opacity").getAsFloat(); + if (opacity <= 1f) { + pen.setOpacity(opacity); + } else if (opacity <= 255f) { + pen.setOpacity(opacity / 255f); } } - DrawnElement drawnElement = new DrawnElement(CACHED_SHAPES.get(shapeName), pen); - drawnElement.setPen(pen); - ZoneRenderer zoneRenderer = FunctionUtil.getZoneRenderer(functionName, mapName); - MapToolEventQueue.invokeLater( - () -> { - zoneRenderer.getZone().addDrawable(drawnElement); - MapTool.getFrame().updateDrawTree(); - MapTool.getFrame().refresh(); - }); - - return drawnElement.getDrawable().getId(); - } else { - return false; + if (penObject.keySet().contains("eraser")) { + pen.setEraser(penObject.get("eraser").getAsBoolean()); + } } + DrawnElement drawnElement = new DrawnElement(CACHED_SHAPES.get(shapeName), pen); + drawnElement.setPen(pen); + FunctionUtil.getZoneRenderer(functionName, mapName).getZone().addDrawable(drawnElement); + MapTool.getFrame().updateDrawTree(); + MapTool.getFrame().refresh(); + + return drawnElement.getDrawable().getId(); } private Object getProperties( Parser parser, VariableResolver resolver, String functionName, List parameters) throws ParserException { - /* - name, delimiter - */ + // name, delimiter String name = FunctionUtil.paramAsString(functionName, parameters, 0, false); String delimiter = parameters.size() < 2 @@ -424,9 +489,9 @@ private Object shapeList( private Object transformShape( Parser parser, VariableResolver resolver, String functionName, List parameters) throws ParserException { - FunctionUtil.checkNumberParam(functionName, parameters, 5, 5); + FunctionUtil.checkNumberParam(functionName, parameters, 4, 6); /* - name, layer, anti-aliasing, shape name to transform, transforms + name, layer, anti-aliasing, shape name to transform, transforms, delimiter */ Object[] leadParams = getLeadParameters(functionName, parameters); GUID guid = (GUID) leadParams[0]; @@ -434,11 +499,16 @@ private Object transformShape( Zone.Layer layer = (Zone.Layer) leadParams[2]; boolean aa = (boolean) leadParams[3]; + String delimiter = ","; + if (parameters.size() > 5) { + delimiter = FunctionUtil.paramAsString(functionName, parameters, 5, false); + } String shapeName = FunctionUtil.paramAsString(functionName, parameters, 3, false); if (!CACHED_SHAPES.containsKey(shapeName)) { throw new ParserException(I18N.getText(OBJECT_NOT_FOUND, functionName, shapeName)); } - Shape shape = transform(CACHED_SHAPES.get(shapeName).getShape(), functionName, parameters, 4); + Shape shape = + transform(CACHED_SHAPES.get(shapeName).getShape(), functionName, parameters, 4, delimiter); ShapeDrawable sd = new ShapeDrawable(guid, shape, aa); sd.setName(name); if (layer != null) { @@ -481,78 +551,70 @@ private Object[] getLeadParameters(String functionName, List parameters) return results; } - private Shape arc(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys( - jsonObject, Set.of("x", "y", "w", "h", "start", "extent", "type"), 4, functionName); + private Shape arc(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames( + shapeParameters, + Set.of("x", "y", "w", "h", "start", "extent", "type"), + 4, + functionName, + ""); return new Arc2D.Float( - jsonObject.get("x").getAsFloat(), - jsonObject.get("y").getAsFloat(), - jsonObject.get("w").getAsFloat(), - jsonObject.get("h").getAsFloat(), - jsonObject.get("start").getAsFloat(), - jsonObject.get("extent").getAsFloat(), - switch (jsonObject.get("type").getAsString().toLowerCase()) { + shapeParameters.get("x").getAsFloat(), + shapeParameters.get("y").getAsFloat(), + shapeParameters.get("w").getAsFloat(), + shapeParameters.get("h").getAsFloat(), + shapeParameters.get("start").getAsFloat(), + shapeParameters.get("extent").getAsFloat(), + switch (shapeParameters.get("type").getAsString().toLowerCase()) { case "chord", "1" -> Arc2D.CHORD; case "pie", "2" -> Arc2D.PIE; default -> Arc2D.OPEN; }); } - private Shape cubicCurve(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys( - jsonObject, + private Shape cubicCurve(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames( + shapeParameters, Set.of("x1", "y1", "ctrlx1", "ctrly1", "ctrlx2", "ctrly2", "x2", "y2"), 4, - functionName); + functionName, + ""); return new CubicCurve2D.Float( - jsonObject.get("x1").getAsFloat(), - jsonObject.get("y1").getAsFloat(), - jsonObject.get("ctrlx1").getAsFloat(), - jsonObject.get("ctrly1").getAsFloat(), - jsonObject.get("ctrlx2").getAsFloat(), - jsonObject.get("ctrly2").getAsFloat(), - jsonObject.get("x2").getAsFloat(), - jsonObject.get("y2").getAsFloat()); + shapeParameters.get("x1").getAsFloat(), + shapeParameters.get("y1").getAsFloat(), + shapeParameters.get("ctrlx1").getAsFloat(), + shapeParameters.get("ctrly1").getAsFloat(), + shapeParameters.get("ctrlx2").getAsFloat(), + shapeParameters.get("ctrly2").getAsFloat(), + shapeParameters.get("x2").getAsFloat(), + shapeParameters.get("y2").getAsFloat()); } - private Shape ellipse(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys(jsonObject, Set.of("x", "y", "w", "h"), 4, functionName); + private Shape ellipse(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames(shapeParameters, Set.of("x", "y", "w", "h"), 4, functionName, ""); return new Ellipse2D.Float( - jsonObject.get("x").getAsFloat(), - jsonObject.get("y").getAsFloat(), - jsonObject.get("w").getAsFloat(), - jsonObject.get("h").getAsFloat()); + shapeParameters.get("x").getAsFloat(), + shapeParameters.get("y").getAsFloat(), + shapeParameters.get("w").getAsFloat(), + shapeParameters.get("h").getAsFloat()); } - private Shape line(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys(jsonObject, Set.of("x1", "y1", "x2", "y2"), 4, functionName); + private Shape line(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames( + shapeParameters, Set.of("x1", "y1", "x2", "y2"), 4, functionName, ""); return new Line2D.Float( - jsonObject.get("x1").getAsFloat(), - jsonObject.get("y1").getAsFloat(), - jsonObject.get("x2").getAsFloat(), - jsonObject.get("y2").getAsFloat()); + shapeParameters.get("x1").getAsFloat(), + shapeParameters.get("y1").getAsFloat(), + shapeParameters.get("x2").getAsFloat(), + shapeParameters.get("y2").getAsFloat()); } - private Shape path(String functionName, List parameters) throws ParserException { - JsonArray jsonArray = - FunctionUtil.paramConvertedToJson(functionName, parameters, 4).getAsJsonArray(); + private Shape path(String functionName, JsonArray pathArray) throws ParserException { ExtendedGeneralPath path = new ExtendedGeneralPath(); - for (JsonElement jsonElement : jsonArray) { + for (JsonElement jsonElement : pathArray) { JsonArray segment = null; try { segment = jsonElement.getAsJsonArray(); @@ -595,72 +657,59 @@ private Shape path(String functionName, List parameters) throws ParserEx return path; } - private Shape polygon(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys( - jsonObject, Set.of("xpoints", "ypoints", "numpoints"), 4, functionName); + private Shape polygon(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames( + shapeParameters, Set.of("xpoints", "ypoints", "numpoints"), 4, functionName, ""); float[] xpts = Floats.toArray( - jsonObject.get("xpoints").getAsJsonArray().asList().stream() + shapeParameters.get("xpoints").getAsJsonArray().asList().stream() .map(JsonElement::getAsDouble) .toList()); float[] ypts = Floats.toArray( - jsonObject.get("ypoints").getAsJsonArray().asList().stream() + shapeParameters.get("ypoints").getAsJsonArray().asList().stream() .map(JsonElement::getAsDouble) .toList()); - return new Polygon2D(xpts, ypts, jsonObject.get("numpoints").getAsInt()); + return new Polygon2D(xpts, ypts, shapeParameters.get("numpoints").getAsInt()); } - private Shape quadCurve(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys( - jsonObject, Set.of("x1", "y1", "ctrlx", "ctrly", "x2", "y2"), 4, functionName); + private Shape quadCurve(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames( + shapeParameters, Set.of("x1", "y1", "ctrlx", "ctrly", "x2", "y2"), 4, functionName, ""); return new QuadCurve2D.Float( - jsonObject.get("x1").getAsFloat(), - jsonObject.get("y1").getAsFloat(), - jsonObject.get("ctrlx").getAsFloat(), - jsonObject.get("ctrly").getAsFloat(), - jsonObject.get("x2").getAsFloat(), - jsonObject.get("y2").getAsFloat()); + shapeParameters.get("x1").getAsFloat(), + shapeParameters.get("y1").getAsFloat(), + shapeParameters.get("ctrlx").getAsFloat(), + shapeParameters.get("ctrly").getAsFloat(), + shapeParameters.get("x2").getAsFloat(), + shapeParameters.get("y2").getAsFloat()); } - private Shape rectangle(String functionName, List parameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys(jsonObject, Set.of("x", "y", "w", "h"), 4, functionName); + private Shape rectangle(String functionName, JsonObject shapeParameters) throws ParserException { + FunctionUtil.validateKeyNames(shapeParameters, Set.of("x", "y", "w", "h"), 4, functionName, ""); return new Rectangle2D.Float( - jsonObject.get("x").getAsFloat(), - jsonObject.get("y").getAsFloat(), - jsonObject.get("w").getAsFloat(), - jsonObject.get("h").getAsFloat()); + shapeParameters.get("x").getAsFloat(), + shapeParameters.get("y").getAsFloat(), + shapeParameters.get("w").getAsFloat(), + shapeParameters.get("h").getAsFloat()); } - private Shape roundRectangle(String functionName, List parameters) + private Shape roundRectangle(String functionName, JsonObject shapeParameters) throws ParserException { - JsonObject jsonObject = - FunctionUtil.jsonWithLowerCaseKeys( - FunctionUtil.paramFromStrPropOrJsonAsJsonObject(functionName, parameters, 4)); - FunctionUtil.validateJsonKeys( - jsonObject, Set.of("x", "y", "w", "h", "arcw", "arch"), 4, functionName); + FunctionUtil.validateKeyNames( + shapeParameters, Set.of("x", "y", "w", "h", "arcw", "arch"), 4, functionName, ""); return new RoundRectangle2D.Float( - jsonObject.get("x").getAsFloat(), - jsonObject.get("y").getAsFloat(), - jsonObject.get("w").getAsFloat(), - jsonObject.get("h").getAsFloat(), - jsonObject.get("arcw").getAsFloat(), - jsonObject.get("arch").getAsFloat()); + shapeParameters.get("x").getAsFloat(), + shapeParameters.get("y").getAsFloat(), + shapeParameters.get("w").getAsFloat(), + shapeParameters.get("h").getAsFloat(), + shapeParameters.get("arcw").getAsFloat(), + shapeParameters.get("arch").getAsFloat()); } - private Shape svgPath(String functionName, List parameters) throws ParserException { - String pathString = FunctionUtil.paramAsString(functionName, parameters, 4, false); + private Shape svgPath(String functionName, String pathString) throws ParserException { try { PATH_PARSER.parse(pathString); final Path2D path = new Path2D.Double(AWT_PATH_PRODUCER.getShape()); @@ -672,17 +721,24 @@ private Shape svgPath(String functionName, List parameters) throws Parse } private Shape transform( - Shape shape, String functionName, List parameters, int transformIndex) + Shape shape, + String functionName, + List parameters, + int transformIndex, + String delimiter) throws ParserException { + JsonArray transforms = new JsonArray(); String transformsString = - FunctionUtil.paramAsString(functionName, parameters, transformIndex, true) - .replaceAll("\\s", ""); - if (transformsString.contains("[")) { - transforms = - (JsonArray) FunctionUtil.paramConvertedToJson(functionName, parameters, transformIndex); + FunctionUtil.paramAsString(functionName, parameters, transformIndex, true); + + if (parameters.get(transformIndex) instanceof JsonArray + || delimiter.equalsIgnoreCase("json") + || transformsString.contains("[")) { + transforms = FunctionUtil.paramAsJsonArray(functionName, parameters, transformIndex); } else { - for (String s : transformsString.split(",")) { + transformsString = transformsString.replaceAll("\\s", ""); + for (String s : transformsString.split(delimiter)) { transforms.add(s); } }