1
0
mirror of https://github.com/octoleo/plantuml.git synced 2025-04-07 02:31:51 +00:00

Merge branch 'wip'

This commit is contained in:
Arnaud Roques 2022-01-27 18:08:23 +01:00
commit 6fb89e85e7
10 changed files with 156 additions and 149 deletions

View File

@ -104,23 +104,20 @@ public class Link extends WithLinkType implements Hideable, Removeable {
private Url url; private Url url;
public String idCommentForSvg() { public String idCommentForSvg() {
if (type.looksLikeRevertedForSvg()) { if (type.looksLikeRevertedForSvg())
final String comment = getEntity1().getCodeGetName() + "-backto-" + getEntity2().getCodeGetName(); return getEntity1().getCodeGetName() + "-backto-" + getEntity2().getCodeGetName();
return comment;
} if (type.looksLikeNoDecorAtAllSvg())
if (type.looksLikeNoDecorAtAllSvg()) { return getEntity1().getCodeGetName() + "-" + getEntity2().getCodeGetName();
final String comment = getEntity1().getCodeGetName() + "-" + getEntity2().getCodeGetName();
return comment; return getEntity1().getCodeGetName() + "-to-" + getEntity2().getCodeGetName();
}
final String comment = getEntity1().getCodeGetName() + "-to-" + getEntity2().getCodeGetName();
return comment;
} }
public UComment commentForSvg() { public UComment commentForSvg() {
if (type.looksLikeRevertedForSvg()) { if (type.looksLikeRevertedForSvg())
return new UComment( return new UComment(
"reverse link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName()); "reverse link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName());
}
return new UComment("link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName()); return new UComment("link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName());
} }
@ -158,33 +155,15 @@ public class Link extends WithLinkType implements Hideable, Removeable {
this.labeldistance = labeldistance; this.labeldistance = labeldistance;
this.labelangle = labelangle; this.labelangle = labelangle;
this.setSpecificColor(specificColor); this.setSpecificColor(specificColor);
if (qualifier1 != null) { if (qualifier1 != null)
((ILeaf) cl1).setNearDecoration(true); ((ILeaf) cl1).setNearDecoration(true);
}
if (qualifier2 != null) { if (qualifier2 != null)
((ILeaf) cl2).setNearDecoration(true); ((ILeaf) cl2).setNearDecoration(true);
}
// if (type.getDecor2() == LinkDecor.EXTENDS) {
// setSametail(cl1.getUid());
// }
} }
// private static boolean doWeHaveToRemoveUrlAtStart(Display label) {
// if (label.size() == 0) {
// return false;
// }
// final String s = label.get(0).toString();
// if (s.matches("^\\[\\[\\S+\\]\\].+$")) {
// return true;
// }
// return false;
// }
public Link getInv() { public Link getInv() {
// if (getLength() == 1) {
// final int x = cl1.getXposition();
// cl2.setXposition(x-1);
// }
final Link result = new Link(cl2, cl1, getType().getInversed(), label, length, qualifier2, qualifier1, final Link result = new Link(cl2, cl1, getType().getInversed(), label, length, qualifier2, qualifier1,
labeldistance, labelangle, getSpecificColor(), styleBuilder); labeldistance, labelangle, getSpecificColor(), styleBuilder);
result.inverted = !this.inverted; result.inverted = !this.inverted;
@ -193,6 +172,7 @@ public class Link extends WithLinkType implements Hideable, Removeable {
result.url = this.url; result.url = this.url;
result.linkConstraint = this.linkConstraint; result.linkConstraint = this.linkConstraint;
result.stereotype = stereotype; result.stereotype = stereotype;
result.visibilityModifier = visibilityModifier;
return result; return result;
} }
@ -216,9 +196,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
public final boolean isInvis() { public final boolean isInvis() {
if (type.isInvisible()) { if (type.isInvisible())
return true; return true;
}
return invis; return invis;
} }
@ -227,12 +207,12 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
public boolean isBetween(IEntity cl1, IEntity cl2) { public boolean isBetween(IEntity cl1, IEntity cl2) {
if (cl1.equals(this.cl1) && cl2.equals(this.cl2)) { if (cl1.equals(this.cl1) && cl2.equals(this.cl2))
return true; return true;
}
if (cl1.equals(this.cl2) && cl2.equals(this.cl1)) { if (cl1.equals(this.cl2) && cl2.equals(this.cl1))
return true; return true;
}
return false; return false;
} }
@ -259,40 +239,40 @@ public class Link extends WithLinkType implements Hideable, Removeable {
@Override @Override
public LinkType getType() { public LinkType getType() {
if (opale) { if (opale)
return new LinkType(LinkDecor.NONE, LinkDecor.NONE); return new LinkType(LinkDecor.NONE, LinkDecor.NONE);
}
if (getSametail() != null) { if (getSametail() != null)
return new LinkType(LinkDecor.NONE, LinkDecor.NONE); return new LinkType(LinkDecor.NONE, LinkDecor.NONE);
}
LinkType result = type; LinkType result = type;
if (OptionFlags.USE_INTERFACE_EYE1) { if (OptionFlags.USE_INTERFACE_EYE1) {
if (isLollipopInterfaceEye(cl1)) { if (isLollipopInterfaceEye(cl1))
type = type.withLollipopInterfaceEye1(); type = type.withLollipopInterfaceEye1();
}
if (isLollipopInterfaceEye(cl2)) { if (isLollipopInterfaceEye(cl2))
type = type.withLollipopInterfaceEye2(); type = type.withLollipopInterfaceEye2();
}
} }
return result; return result;
} }
private boolean isReallyGroup(IEntity ent) { private boolean isReallyGroup(IEntity ent) {
if (ent.isGroup() == false) { if (ent.isGroup() == false)
return false; return false;
}
final IGroup group = (IGroup) ent; final IGroup group = (IGroup) ent;
return group.getChildren().size() + group.getLeafsDirect().size() > 0; return group.getChildren().size() + group.getLeafsDirect().size() > 0;
} }
public LinkType getTypePatchCluster() { public LinkType getTypePatchCluster() {
LinkType result = getType(); LinkType result = getType();
if (isReallyGroup(getEntity1())) { if (isReallyGroup(getEntity1()))
result = result.withoutDecors2(); result = result.withoutDecors2();
}
if (isReallyGroup(getEntity2())) { if (isReallyGroup(getEntity2()))
result = result.withoutDecors1(); result = result.withoutDecors1();
}
return result; return result;
} }
@ -302,12 +282,12 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
LinkType result = type; LinkType result = type;
if (OptionFlags.USE_INTERFACE_EYE1) { if (OptionFlags.USE_INTERFACE_EYE1) {
if (isLollipopInterfaceEye(cl1)) { if (isLollipopInterfaceEye(cl1))
type = type.withLollipopInterfaceEye1(); type = type.withLollipopInterfaceEye1();
}
if (isLollipopInterfaceEye(cl2)) { if (isLollipopInterfaceEye(cl2))
type = type.withLollipopInterfaceEye2(); type = type.withLollipopInterfaceEye2();
}
} }
return result; return result;
} }
@ -375,39 +355,39 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
public boolean isAutoLinkOfAGroup() { public boolean isAutoLinkOfAGroup() {
if (getEntity1().isGroup() == false) { if (getEntity1().isGroup() == false)
return false; return false;
}
if (getEntity2().isGroup() == false) { if (getEntity2().isGroup() == false)
return false; return false;
}
if (getEntity1() == getEntity2()) { if (getEntity1() == getEntity2())
return true; return true;
}
return false; return false;
} }
public boolean containsType(LeafType type) { public boolean containsType(LeafType type) {
if (getEntity1().getLeafType() == type || getEntity2().getLeafType() == type) { if (getEntity1().getLeafType() == type || getEntity2().getLeafType() == type)
return true; return true;
}
return false; return false;
} }
public boolean contains(IEntity entity) { public boolean contains(IEntity entity) {
if (getEntity1() == entity || getEntity2() == entity) { if (getEntity1() == entity || getEntity2() == entity)
return true; return true;
}
return false; return false;
} }
public IEntity getOther(IEntity entity) { public IEntity getOther(IEntity entity) {
if (getEntity1() == entity) { if (getEntity1() == entity)
return getEntity2(); return getEntity2();
}
if (getEntity2() == entity) { if (getEntity2() == entity)
return getEntity1(); return getEntity1();
}
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@ -455,9 +435,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
public final LinkArrow getLinkArrow() { public final LinkArrow getLinkArrow() {
if (inverted) { if (inverted)
return linkArrow.reverse(); return linkArrow.reverse();
}
return linkArrow; return linkArrow;
} }
@ -495,28 +475,28 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
public boolean sameConnections(Link other) { public boolean sameConnections(Link other) {
if (this.cl1 == other.cl1 && this.cl2 == other.cl2) { if (this.cl1 == other.cl1 && this.cl2 == other.cl2)
return true; return true;
}
if (this.cl1 == other.cl2 && this.cl2 == other.cl1) { if (this.cl1 == other.cl2 && this.cl2 == other.cl1)
return true; return true;
}
return false; return false;
} }
public boolean doesTouch(Link other) { public boolean doesTouch(Link other) {
if (this.cl1 == other.cl1) { if (this.cl1 == other.cl1)
return true; return true;
}
if (this.cl1 == other.cl2) { if (this.cl1 == other.cl2)
return true; return true;
}
if (this.cl2 == other.cl1) { if (this.cl2 == other.cl1)
return true; return true;
}
if (this.cl2 == other.cl2) { if (this.cl2 == other.cl2)
return true; return true;
}
return false; return false;
} }
@ -529,9 +509,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
} }
public boolean hasUrl() { public boolean hasUrl() {
if (Display.isNull(label) == false && label.hasUrl()) { if (Display.isNull(label) == false && label.hasUrl())
return true; return true;
}
return getUrl() != null; return getUrl() != null;
} }
@ -546,12 +526,12 @@ public class Link extends WithLinkType implements Hideable, Removeable {
public void setPortMembers(String port1, String port2) { public void setPortMembers(String port1, String port2) {
this.port1 = port1; this.port1 = port1;
this.port2 = port2; this.port2 = port2;
if (port1 != null) { if (port1 != null)
((ILeaf) cl1).addPortShortName(port1); ((ILeaf) cl1).addPortShortName(port1);
}
if (port2 != null) { if (port2 != null)
((ILeaf) cl2).addPortShortName(port2); ((ILeaf) cl2).addPortShortName(port2);
}
} }
public final VisibilityModifier getVisibilityModifier() { public final VisibilityModifier getVisibilityModifier() {
@ -581,9 +561,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
private LineLocation codeLine; private LineLocation codeLine;
public String getCodeLine() { public String getCodeLine() {
if (codeLine == null) { if (codeLine == null)
return null; return null;
}
return "" + codeLine.getPosition(); return "" + codeLine.getPosition();
} }

View File

@ -43,6 +43,7 @@ import java.util.StringTokenizer;
import net.sourceforge.plantuml.BackSlash; import net.sourceforge.plantuml.BackSlash;
import net.sourceforge.plantuml.Log; import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.ugraphic.ShadowManager; import net.sourceforge.plantuml.ugraphic.ShadowManager;
import net.sourceforge.plantuml.ugraphic.UPath; import net.sourceforge.plantuml.ugraphic.UPath;
import net.sourceforge.plantuml.ugraphic.USegment; import net.sourceforge.plantuml.ugraphic.USegment;
@ -790,6 +791,10 @@ public class EpsGraphics {
} }
public void openLink(String url) { public void openLink(String url) {
// javascript: security issue
if (SecurityUtils.ignoreThisLink(url))
return;
this.urlArea = new UrlArea(url); this.urlArea = new UrlArea(url);
} }

View File

@ -78,11 +78,13 @@ public abstract class UGraphicDelegator implements UGraphic {
public ColorMapper getColorMapper() { public ColorMapper getColorMapper() {
return ug.getColorMapper(); return ug.getColorMapper();
} }
@Override
public void startUrl(Url url) { public void startUrl(Url url) {
ug.startUrl(url); ug.startUrl(url);
} }
@Override
public void closeUrl() { public void closeUrl() {
ug.closeUrl(); ug.closeUrl();
} }

View File

@ -97,29 +97,29 @@ public class SecurityUtils {
public static final String PATHS_ALLOWED = "plantuml.allowlist.path"; public static final String PATHS_ALLOWED = "plantuml.allowlist.path";
/** /**
* Paths to folders with security specific content (not allowed to read via SFile). * Paths to folders with security specific content (not allowed to read via
* SFile).
*/ */
public static final String PATHS_SECURITY = "plantuml.security.credentials.path"; public static final String PATHS_SECURITY = "plantuml.security.credentials.path";
public static final String SECURITY_ALLOW_NONSSL_AUTH = "plantuml.security.allowNonSSLAuth"; public static final String SECURITY_ALLOW_NONSSL_AUTH = "plantuml.security.allowNonSSLAuth";
/** /**
* Standard BasicAuth authentication interceptor, to generate a SecurityAuthentication from credentials. * Standard BasicAuth authentication interceptor, to generate a
* SecurityAuthentication from credentials.
*/ */
private static final SecurityAuthorizeManager PUBLIC_AUTH_MANAGER private static final SecurityAuthorizeManager PUBLIC_AUTH_MANAGER = new SecurityDefaultNoopAuthorizeManager();
= new SecurityDefaultNoopAuthorizeManager();
/** /**
* Standard interceptor for public endpoint access. * Standard interceptor for public endpoint access.
*/ */
private static final SecurityAccessInterceptor PUBLIC_ACCESS_INTERCEPTOR private static final SecurityAccessInterceptor PUBLIC_ACCESS_INTERCEPTOR = new SecurityDefaultNoopAccessInterceptor();
= new SecurityDefaultNoopAccessInterceptor();
/** /**
* Standard TokenAuth authorize manager, to generate a SecurityAuthentication from credentials. * Standard TokenAuth authorize manager, to generate a SecurityAuthentication
* from credentials.
*/ */
private static final SecurityAuthorizeManager TOKEN_AUTH_MANAGER private static final SecurityAuthorizeManager TOKEN_AUTH_MANAGER = new TokenAuthAuthorizeManager();
= new TokenAuthAuthorizeManager();
/** /**
* Standard token access interceptor. * Standard token access interceptor.
@ -127,10 +127,10 @@ public class SecurityUtils {
private static final SecurityAccessInterceptor TOKEN_ACCESS_INTERCEPTOR = new TokenAuthAccessInterceptor(); private static final SecurityAccessInterceptor TOKEN_ACCESS_INTERCEPTOR = new TokenAuthAccessInterceptor();
/** /**
* Standard BasicAuth authorize manager, to generate a SecurityAuthentication from credentials. * Standard BasicAuth authorize manager, to generate a SecurityAuthentication
* from credentials.
*/ */
private static final SecurityAuthorizeManager BASICAUTH_AUTH_MANAGER private static final SecurityAuthorizeManager BASICAUTH_AUTH_MANAGER = new BasicAuthAuthorizeManager();
= new BasicAuthAuthorizeManager();
/** /**
* Standard BasicAuth access interceptor. * Standard BasicAuth access interceptor.
@ -140,14 +140,12 @@ public class SecurityUtils {
/** /**
* OAuth2 client credentials authorization manager. * OAuth2 client credentials authorization manager.
*/ */
private static final SecurityAuthorizeManager OAUTH2_CLIENT_AUTH_MANAGER private static final SecurityAuthorizeManager OAUTH2_CLIENT_AUTH_MANAGER = new OAuth2ClientAccessAuthorizeManager();
= new OAuth2ClientAccessAuthorizeManager();
/** /**
* OAuth2 resource owner authorization manager. * OAuth2 resource owner authorization manager.
*/ */
private static final SecurityAuthorizeManager OAUTH2_RESOURCEOWNER_AUTH_MANAGER private static final SecurityAuthorizeManager OAUTH2_RESOURCEOWNER_AUTH_MANAGER = new OAuth2ResourceOwnerAccessAuthorizeManager();
= new OAuth2ResourceOwnerAccessAuthorizeManager();
/** /**
* Standard 'bearer' OAuth2 access interceptor. * Standard 'bearer' OAuth2 access interceptor.
@ -168,15 +166,19 @@ public class SecurityUtils {
return current; return current;
} }
public static boolean getJavascriptUnsecure() { public static boolean ignoreThisLink(String url) {
final String env = getenv("PLANTUML_JAVASCRIPT_UNSECURE"); if (allowJavascriptInLink() == false && isJavascriptLink(url))
if ("true".equalsIgnoreCase(env)) {
return true; return true;
} return false;
if ("false".equalsIgnoreCase(env)) { }
return false;
} private static boolean isJavascriptLink(String url) {
return OptionFlags.ALLOW_INCLUDE; return url.toLowerCase().replaceAll("[^a-z]", "").startsWith("javascript");
}
private static boolean allowJavascriptInLink() {
final String env = getenv("PLANTUML_ALLOW_JAVASCRIPT_IN_LINK");
return "true".equalsIgnoreCase(env);
} }
public static String getenv(String name) { public static String getenv(String name) {
@ -188,8 +190,8 @@ public class SecurityUtils {
} }
/** /**
* Checks the environment variable and returns true if the variable is used in security context. In this case, the * Checks the environment variable and returns true if the variable is used in
* value should not be displayed in scripts. * security context. In this case, the value should not be displayed in scripts.
* *
* @param name Environment variable to check * @param name Environment variable to check
* @return true, if this is a secret variable * @return true, if this is a secret variable
@ -201,7 +203,8 @@ public class SecurityUtils {
/** /**
* Configuration for Non-SSL authentication methods. * Configuration for Non-SSL authentication methods.
* *
* @return true, if plantUML should allow authentication in plain connections (without encryption). * @return true, if plantUML should allow authentication in plain connections
* (without encryption).
* @see #SECURITY_ALLOW_NONSSL_AUTH * @see #SECURITY_ALLOW_NONSSL_AUTH
*/ */
public static boolean isNonSSLAuthenticationAllowed() { public static boolean isNonSSLAuthenticationAllowed() {
@ -336,7 +339,8 @@ public class SecurityUtils {
public static boolean existsSecurityCredentials(String userToken) { public static boolean existsSecurityCredentials(String userToken) {
SFile securityPath = getSecurityPath(); SFile securityPath = getSecurityPath();
if (securityPath != null) { if (securityPath != null) {
// SFile does not allow access to the security path (to hide the credentials in DSL scripts) // SFile does not allow access to the security path (to hide the credentials in
// DSL scripts)
File securityFilePath = securityPath.conv(); File securityFilePath = securityPath.conv();
File userCredentials = new File(securityFilePath, userToken + ".credential"); File userCredentials = new File(securityFilePath, userToken + ".credential");
return userCredentials.exists() && userCredentials.canRead() && !userCredentials.isDirectory() return userCredentials.exists() && userCredentials.canRead() && !userCredentials.isDirectory()
@ -356,7 +360,8 @@ public class SecurityUtils {
if (userToken != null && checkFileSystemSaveCharactersStrict(userToken) && !NO_CREDENTIALS.equals(userToken)) { if (userToken != null && checkFileSystemSaveCharactersStrict(userToken) && !NO_CREDENTIALS.equals(userToken)) {
final SFile securityPath = getSecurityPath(); final SFile securityPath = getSecurityPath();
if (securityPath != null) { if (securityPath != null) {
// SFile does not allow access to the security path (to hide the credentials in DSL scripts) // SFile does not allow access to the security path (to hide the credentials in
// DSL scripts)
File securityFilePath = securityPath.conv(); File securityFilePath = securityPath.conv();
File userCredentials = new File(securityFilePath, userToken + ".credential"); File userCredentials = new File(securityFilePath, userToken + ".credential");
JsonValue jsonValue = loadJson(userCredentials); JsonValue jsonValue = loadJson(userCredentials);
@ -367,8 +372,8 @@ public class SecurityUtils {
} }
/** /**
* Checks, if the token of a pathname (filename, ext, directory-name) uses only a very strict set of characters and * Checks, if the token of a pathname (filename, ext, directory-name) uses only
* not longer than 64 characters. * a very strict set of characters and not longer than 64 characters.
* <p> * <p>
* Only characters from a to Z, Numbers and - are allowed. * Only characters from a to Z, Numbers and - are allowed.
* *
@ -377,15 +382,16 @@ public class SecurityUtils {
* @see #SECURE_CHARS * @see #SECURE_CHARS
*/ */
private static boolean checkFileSystemSaveCharactersStrict(String pathNameToken) { private static boolean checkFileSystemSaveCharactersStrict(String pathNameToken) {
return StringUtils.isNotEmpty(pathNameToken) return StringUtils.isNotEmpty(pathNameToken) && SECURE_CHARS.matcher(pathNameToken).matches()
&& SECURE_CHARS.matcher(pathNameToken).matches() && pathNameToken.length() <= 64; && pathNameToken.length() <= 64;
} }
/** /**
* Loads the path to the configured security folder, if existing. * Loads the path to the configured security folder, if existing.
* <p> * <p>
* Please note: A SFile referenced to a security folder cannot access the files. The content of the files in the * Please note: A SFile referenced to a security folder cannot access the files.
* security path should never have passed to DSL scripts. * The content of the files in the security path should never have passed to DSL
* scripts.
* *
* @return SFile folder or null * @return SFile folder or null
*/ */
@ -401,9 +407,9 @@ public class SecurityUtils {
return null; return null;
} }
/** /**
* Loads a file as JSON object. If no file exists or the file is not parsable, the method returns an empty JSON. * Loads a file as JSON object. If no file exists or the file is not parsable,
* the method returns an empty JSON.
* *
* @param jsonFile file path to the JSON file * @param jsonFile file path to the JSON file
* @return a Json vale (maybe empty) * @return a Json vale (maybe empty)

View File

@ -912,9 +912,9 @@ public class SvgGraphics {
Objects.requireNonNull(url); Objects.requireNonNull(url);
// javascript: security issue // javascript: security issue
if (SecurityUtils.getJavascriptUnsecure() == false && url.toLowerCase().startsWith("javascript")) { if (SecurityUtils.ignoreThisLink(url))
return; return;
}
if (pendingAction.size() > 0) { if (pendingAction.size() > 0) {
closeLink(); closeLink();

View File

@ -173,9 +173,11 @@ public abstract class AbstractCommonUGraphic implements UGraphic {
final public void flushUg() { final public void flushUg() {
} }
@Override
public void startUrl(Url url) { public void startUrl(Url url) {
} }
@Override
public void closeUrl() { public void closeUrl() {
} }

View File

@ -114,10 +114,12 @@ public class UGraphicEps extends AbstractUGraphic<EpsGraphics> implements ClipCo
return ug.getEPSCode(); return ug.getEPSCode();
} }
@Override
public void startUrl(Url url) { public void startUrl(Url url) {
getGraphicObject().openLink(url.getUrl()); getGraphicObject().openLink(url.getUrl());
} }
@Override
public void closeUrl() { public void closeUrl() {
getGraphicObject().closeLink(); getGraphicObject().closeLink();
} }

View File

@ -55,6 +55,7 @@ import net.sourceforge.plantuml.anim.AffineTransformation;
import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.png.PngIO; import net.sourceforge.plantuml.png.PngIO;
import net.sourceforge.plantuml.posimo.DotPath; import net.sourceforge.plantuml.posimo.DotPath;
import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic; import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic;
import net.sourceforge.plantuml.ugraphic.AbstractUGraphic; import net.sourceforge.plantuml.ugraphic.AbstractUGraphic;
import net.sourceforge.plantuml.ugraphic.UAntiAliasing; import net.sourceforge.plantuml.ugraphic.UAntiAliasing;
@ -82,7 +83,7 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
private UAntiAliasing antiAliasing = UAntiAliasing.ANTI_ALIASING_ON; private UAntiAliasing antiAliasing = UAntiAliasing.ANTI_ALIASING_ON;
private/* final */List<Url> urls = new ArrayList<>(); private List<Url> urls = new ArrayList<>();
private Set<Url> allUrls = new HashSet<>(); private Set<Url> allUrls = new HashSet<>();
private final boolean hasAffineTransform; private final boolean hasAffineTransform;
@ -116,22 +117,22 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
register(dpiFactor); register(dpiFactor);
} }
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d, double dpiFactor) { public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor) {
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, null, 0, 0); this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, null, 0, 0);
} }
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d, double dpiFactor, public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
AffineTransformation affineTransform, double dx, double dy) { double dpiFactor, AffineTransformation affineTransform, double dx, double dy) {
super(defaultBackground, colorMapper, stringBounder, g2d); super(defaultBackground, colorMapper, stringBounder, g2d);
this.hasAffineTransform = affineTransform != null; this.hasAffineTransform = affineTransform != null;
this.dpiFactor = dpiFactor; this.dpiFactor = dpiFactor;
if (dpiFactor != 1.0) { if (dpiFactor != 1.0)
g2d.scale(dpiFactor, dpiFactor); g2d.scale(dpiFactor, dpiFactor);
}
if (this.hasAffineTransform) { if (this.hasAffineTransform) {
if (dx != 0 || dy != 0) { if (dx != 0 || dy != 0)
getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy)); getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy));
}
getGraphicObject().transform(affineTransform.getAffineTransform()); getGraphicObject().transform(affineTransform.getAffineTransform());
} }
register(dpiFactor); register(dpiFactor);
@ -176,21 +177,28 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
return dpiFactor; return dpiFactor;
} }
@Override
public void startUrl(Url url) { public void startUrl(Url url) {
urls.add(Objects.requireNonNull(url)); Objects.requireNonNull(url);
allUrls.add(url); // javascript: security issue
if (SecurityUtils.ignoreThisLink(url.getUrl())) {
urls.add(null);
} else {
urls.add(url);
allUrls.add(url);
}
} }
@Override
public void closeUrl() { public void closeUrl() {
urls.remove(urls.size() - 1); urls.remove(urls.size() - 1);
} }
public void ensureVisible(double x, double y) { public void ensureVisible(double x, double y) {
for (Url u : urls) { for (Url u : urls)
if (getClip() == null || getClip().isInside(x, y)) { if (u != null && (getClip() == null || getClip().isInside(x, y)))
u.ensureVisible(x, y); u.ensureVisible(x, y);
}
}
} }
public BufferedImage getBufferedImage() { public BufferedImage getBufferedImage() {

View File

@ -89,10 +89,12 @@ public class UGraphicTikz extends AbstractUGraphic<TikzGraphics> implements Clip
registerDriver(UCenteredCharacter.class, new DriverCenteredCharacterTikz2()); registerDriver(UCenteredCharacter.class, new DriverCenteredCharacterTikz2());
} }
@Override
public void startUrl(Url url) { public void startUrl(Url url) {
getGraphicObject().openLink(url.getUrl(), url.getTooltip()); getGraphicObject().openLink(url.getUrl(), url.getTooltip());
} }
@Override
public void closeUrl() { public void closeUrl() {
getGraphicObject().closeLink(); getGraphicObject().closeLink();
} }

View File

@ -80,7 +80,7 @@ public class Version {
} }
public static int beta() { public static int beta() {
final int beta = 5; final int beta = 6;
return beta; return beta;
} }