svg style inheritance fix

This commit is contained in:
honfika@gmail.com
2015-12-28 08:30:16 +01:00
parent 5ab44babae
commit 27cdd48a1f
3 changed files with 421 additions and 468 deletions

View File

@@ -121,8 +121,7 @@ public class SvgImporter {
throw new IOException("SVG root element should be 'svg'");
}
SvgStyle style = new SvgStyle(this);
style = style.apply(rootElement, idMap);
SvgStyle style = new SvgStyle(this, idMap, rootElement);
Matrix transform = new Matrix();
processSvgObject(idMap, shapeNum, shapes, rootElement, transform, style);
} catch (SAXException | IOException | ParserConfigurationException ex) {
@@ -171,7 +170,7 @@ public class SvgImporter {
if (childNode instanceof Element) {
Element childElement = (Element) childNode;
String tagName = childElement.getTagName();
SvgStyle newStyle = style.apply(childElement, idMap);
SvgStyle newStyle = new SvgStyle(this, idMap, childElement);
Matrix m = Matrix.parseSvgMatrix(childElement.getAttribute("transform"), 1, 1);
Matrix m2 = m == null ? transform : transform.concatenate(m);
if ("g".equals(tagName)) {
@@ -1015,64 +1014,64 @@ public class SvgImporter {
//Test for SVG
public static void main(String[] args) throws IOException, InterruptedException {
svgTest("animate-elem-02-t");
svgTest("animate-elem-03-t");
svgTest("animate-elem-04-t");
svgTest("animate-elem-05-t");
svgTest("animate-elem-06-t");
svgTest("animate-elem-07-t");
svgTest("animate-elem-08-t");
svgTest("animate-elem-09-t");
svgTest("animate-elem-10-t");
svgTest("animate-elem-11-t");
svgTest("animate-elem-12-t");
svgTest("animate-elem-13-t");
svgTest("animate-elem-14-t");
svgTest("animate-elem-15-t");
svgTest("animate-elem-17-t");
svgTest("animate-elem-19-t");
svgTest("animate-elem-20-t");
svgTest("animate-elem-21-t");
svgTest("animate-elem-22-b");
svgTest("animate-elem-23-t");
svgTest("animate-elem-24-t");
svgTest("animate-elem-25-t");
svgTest("animate-elem-26-t");
svgTest("animate-elem-27-t");
svgTest("animate-elem-28-t");
svgTest("animate-elem-29-b");
svgTest("animate-elem-30-t");
svgTest("animate-elem-31-t");
svgTest("animate-elem-32-t");
svgTest("animate-elem-33-t");
svgTest("animate-elem-34-t");
svgTest("animate-elem-36-t");
svgTest("animate-elem-37-t");
svgTest("animate-elem-39-t");
svgTest("animate-elem-40-t");
svgTest("animate-elem-41-t");
svgTest("animate-elem-44-t");
svgTest("animate-elem-46-t");
svgTest("animate-elem-52-t");
svgTest("animate-elem-60-t");
svgTest("animate-elem-61-t");
svgTest("animate-elem-62-t");
svgTest("animate-elem-63-t");
svgTest("animate-elem-64-t");
svgTest("animate-elem-65-t");
svgTest("animate-elem-66-t");
svgTest("animate-elem-67-t");
svgTest("animate-elem-68-t");
svgTest("animate-elem-69-t");
svgTest("animate-elem-70-t");
svgTest("animate-elem-77-t");
svgTest("animate-elem-78-t");
svgTest("animate-elem-80-t");
svgTest("animate-elem-81-t");
svgTest("animate-elem-82-t");
svgTest("animate-elem-83-t");
svgTest("animate-elem-84-t");
svgTest("animate-elem-85-t");
// svgTest("animate-elem-02-t");
// svgTest("animate-elem-03-t");
// svgTest("animate-elem-04-t");
// svgTest("animate-elem-05-t");
// svgTest("animate-elem-06-t");
// svgTest("animate-elem-07-t");
// svgTest("animate-elem-08-t");
// svgTest("animate-elem-09-t");
// svgTest("animate-elem-10-t");
// svgTest("animate-elem-11-t");
// svgTest("animate-elem-12-t");
// svgTest("animate-elem-13-t");
// svgTest("animate-elem-14-t");
// svgTest("animate-elem-15-t");
// svgTest("animate-elem-17-t");
// svgTest("animate-elem-19-t");
// svgTest("animate-elem-20-t");
// svgTest("animate-elem-21-t");
// svgTest("animate-elem-22-b");
// svgTest("animate-elem-23-t");
// svgTest("animate-elem-24-t");
// svgTest("animate-elem-25-t");
// svgTest("animate-elem-26-t");
// svgTest("animate-elem-27-t");
// svgTest("animate-elem-28-t");
// svgTest("animate-elem-29-b");
// svgTest("animate-elem-30-t");
// svgTest("animate-elem-31-t");
// svgTest("animate-elem-32-t");
// svgTest("animate-elem-33-t");
// svgTest("animate-elem-34-t");
// svgTest("animate-elem-36-t");
// svgTest("animate-elem-37-t");
// svgTest("animate-elem-39-t");
// svgTest("animate-elem-40-t");
// svgTest("animate-elem-41-t");
// svgTest("animate-elem-44-t");
// svgTest("animate-elem-46-t");
// svgTest("animate-elem-52-t");
// svgTest("animate-elem-60-t");
// svgTest("animate-elem-61-t");
// svgTest("animate-elem-62-t");
// svgTest("animate-elem-63-t");
// svgTest("animate-elem-64-t");
// svgTest("animate-elem-65-t");
// svgTest("animate-elem-66-t");
// svgTest("animate-elem-67-t");
// svgTest("animate-elem-68-t");
// svgTest("animate-elem-69-t");
// svgTest("animate-elem-70-t");
// svgTest("animate-elem-77-t");
// svgTest("animate-elem-78-t");
// svgTest("animate-elem-80-t");
// svgTest("animate-elem-81-t");
// svgTest("animate-elem-82-t");
// svgTest("animate-elem-83-t");
// svgTest("animate-elem-84-t");
// svgTest("animate-elem-85-t");
svgTest("color-prof-01-f");
svgTest("color-prop-01-b");
svgTest("color-prop-02-f");
@@ -1092,60 +1091,60 @@ public class SvgImporter {
svgTest("coords-viewattr-02-b");
svgTest("coords-viewattr-03-b");
svgTest("extend-namespace-01-f");
svgTest("filters-blend-01-b");
svgTest("filters-color-01-b");
svgTest("filters-composite-02-b");
svgTest("filters-comptran-01-b");
svgTest("filters-conv-01-f");
svgTest("filters-diffuse-01-f");
svgTest("filters-displace-01-f");
svgTest("filters-example-01-b");
svgTest("filters-felem-01-b");
svgTest("filters-gauss-01-b");
svgTest("filters-image-01-b");
svgTest("filters-light-01-f");
svgTest("filters-morph-01-f");
svgTest("filters-offset-01-b");
svgTest("filters-specular-01-f");
svgTest("filters-tile-01-b");
svgTest("filters-turb-01-f");
svgTest("fonts-desc-02-t");
svgTest("fonts-elem-01-t");
svgTest("fonts-elem-02-t");
svgTest("fonts-elem-03-b");
svgTest("fonts-elem-04-b");
svgTest("fonts-elem-05-t");
svgTest("fonts-elem-06-t");
svgTest("fonts-elem-07-b");
svgTest("fonts-glyph-02-t");
svgTest("fonts-glyph-03-t");
svgTest("fonts-glyph-04-t");
svgTest("fonts-kern-01-t");
svgTest("interact-cursor-01-f");
svgTest("interact-dom-01-b");
svgTest("interact-events-01-b");
svgTest("interact-order-01-b");
svgTest("interact-order-02-b");
svgTest("interact-order-03-b");
svgTest("interact-zoom-01-t");
svgTest("linking-a-01-b");
svgTest("linking-a-02-b");
svgTest("linking-a-03-b");
svgTest("linking-a-04-t");
svgTest("linking-a-05-t");
svgTest("linking-a-07-t");
svgTest("linking-uri-01-b");
svgTest("linking-uri-02-b");
svgTest("linking-uri-03-t");
svgTest("masking-intro-01-f");
svgTest("masking-mask-01-b");
svgTest("masking-opacity-01-b");
svgTest("masking-path-01-b");
svgTest("masking-path-02-b");
svgTest("masking-path-03-b");
svgTest("masking-path-04-b");
svgTest("masking-path-05-f");
svgTest("metadata-example-01-b");
// svgTest("filters-blend-01-b");
// svgTest("filters-color-01-b");
// svgTest("filters-composite-02-b");
// svgTest("filters-comptran-01-b");
// svgTest("filters-conv-01-f");
// svgTest("filters-diffuse-01-f");
// svgTest("filters-displace-01-f");
// svgTest("filters-example-01-b");
// svgTest("filters-felem-01-b");
// svgTest("filters-gauss-01-b");
// svgTest("filters-image-01-b");
// svgTest("filters-light-01-f");
// svgTest("filters-morph-01-f");
// svgTest("filters-offset-01-b");
// svgTest("filters-specular-01-f");
// svgTest("filters-tile-01-b");
// svgTest("filters-turb-01-f");
// svgTest("fonts-desc-02-t");
// svgTest("fonts-elem-01-t");
// svgTest("fonts-elem-02-t");
// svgTest("fonts-elem-03-b");
// svgTest("fonts-elem-04-b");
// svgTest("fonts-elem-05-t");
// svgTest("fonts-elem-06-t");
// svgTest("fonts-elem-07-b");
// svgTest("fonts-glyph-02-t");
// svgTest("fonts-glyph-03-t");
// svgTest("fonts-glyph-04-t");
// svgTest("fonts-kern-01-t");
// svgTest("interact-cursor-01-f");
// svgTest("interact-dom-01-b");
// svgTest("interact-events-01-b");
// svgTest("interact-order-01-b");
// svgTest("interact-order-02-b");
// svgTest("interact-order-03-b");
// svgTest("interact-zoom-01-t");
// svgTest("linking-a-01-b");
// svgTest("linking-a-02-b");
// svgTest("linking-a-03-b");
// svgTest("linking-a-04-t");
// svgTest("linking-a-05-t");
// svgTest("linking-a-07-t");
// svgTest("linking-uri-01-b");
// svgTest("linking-uri-02-b");
// svgTest("linking-uri-03-t");
// svgTest("masking-intro-01-f");
// svgTest("masking-mask-01-b");
// svgTest("masking-opacity-01-b");
// svgTest("masking-path-01-b");
// svgTest("masking-path-02-b");
// svgTest("masking-path-03-b");
// svgTest("masking-path-04-b");
// svgTest("masking-path-05-f");
// svgTest("metadata-example-01-b");
svgTest("painting-fill-01-t");
svgTest("painting-fill-02-t");
svgTest("painting-fill-03-t");
@@ -1202,10 +1201,10 @@ public class SvgImporter {
svgTest("render-elems-08-t");
svgTest("render-groups-01-b");
svgTest("render-groups-03-t");
svgTest("script-handle-01-b");
svgTest("script-handle-02-b");
svgTest("script-handle-03-b");
svgTest("script-handle-04-b");
// svgTest("script-handle-01-b");
// svgTest("script-handle-02-b");
// svgTest("script-handle-03-b");
// svgTest("script-handle-04-b");
svgTest("shapes-circle-01-t");
svgTest("shapes-circle-02-t");
svgTest("shapes-ellipse-01-t");
@@ -1216,80 +1215,80 @@ public class SvgImporter {
svgTest("shapes-polyline-01-t");
svgTest("shapes-rect-01-t");
svgTest("shapes-rect-02-t");
svgTest("struct-cond-01-t");
svgTest("struct-cond-02-t");
svgTest("struct-cond-03-t");
svgTest("struct-defs-01-t");
svgTest("struct-dom-01-b");
svgTest("struct-dom-02-b");
svgTest("struct-dom-03-b");
svgTest("struct-dom-04-b");
svgTest("struct-dom-05-b");
svgTest("struct-dom-06-b");
svgTest("struct-frag-01-t");
svgTest("struct-frag-02-t");
svgTest("struct-frag-03-t");
svgTest("struct-frag-04-t");
svgTest("struct-frag-05-t");
svgTest("struct-frag-06-t");
svgTest("struct-group-01-t");
svgTest("struct-group-02-b");
svgTest("struct-group-03-t");
svgTest("struct-image-01-t");
svgTest("struct-image-02-b");
svgTest("struct-image-03-t");
svgTest("struct-image-04-t");
svgTest("struct-image-05-b");
svgTest("struct-image-06-t");
svgTest("struct-image-07-t");
svgTest("struct-image-08-t");
svgTest("struct-image-09-t");
svgTest("struct-image-10-t");
svgTest("struct-symbol-01-b");
svgTest("struct-use-01-t");
svgTest("struct-use-03-t");
svgTest("struct-use-05-b");
svgTest("styling-css-01-b");
svgTest("styling-css-02-b");
svgTest("styling-css-03-b");
svgTest("styling-css-04-f");
svgTest("styling-css-05-b");
svgTest("styling-css-06-b");
svgTest("styling-inherit-01-b");
svgTest("styling-pres-01-t");
svgTest("text-align-01-b");
svgTest("text-align-02-b");
svgTest("text-align-03-b");
svgTest("text-align-04-b");
svgTest("text-align-05-b");
svgTest("text-align-06-b");
svgTest("text-align-08-b");
svgTest("text-altglyph-01-b");
svgTest("text-deco-01-b");
svgTest("text-fonts-01-t");
svgTest("text-fonts-02-t");
svgTest("text-fonts-03-t");
svgTest("text-intro-01-t");
svgTest("text-intro-02-b");
svgTest("text-intro-03-b");
svgTest("text-intro-04-t");
svgTest("text-intro-05-t");
svgTest("text-path-01-b");
svgTest("text-spacing-01-b");
svgTest("text-text-01-b");
svgTest("text-text-03-b");
svgTest("text-text-04-t");
svgTest("text-text-05-t");
svgTest("text-text-06-t");
svgTest("text-text-07-t");
svgTest("text-text-08-b");
svgTest("text-tref-01-b");
svgTest("text-tselect-01-b");
svgTest("text-tselect-02-f");
svgTest("text-tspan-01-b");
svgTest("text-ws-01-t");
svgTest("text-ws-02-t");
svgTest("types-basicDOM-01-b");
// svgTest("struct-cond-01-t");
// svgTest("struct-cond-02-t");
// svgTest("struct-cond-03-t");
// svgTest("struct-defs-01-t");
// svgTest("struct-dom-01-b");
// svgTest("struct-dom-02-b");
// svgTest("struct-dom-03-b");
// svgTest("struct-dom-04-b");
// svgTest("struct-dom-05-b");
// svgTest("struct-dom-06-b");
// svgTest("struct-frag-01-t");
// svgTest("struct-frag-02-t");
// svgTest("struct-frag-03-t");
// svgTest("struct-frag-04-t");
// svgTest("struct-frag-05-t");
// svgTest("struct-frag-06-t");
// svgTest("struct-group-01-t");
// svgTest("struct-group-02-b");
// svgTest("struct-group-03-t");
// svgTest("struct-image-01-t");
// svgTest("struct-image-02-b");
// svgTest("struct-image-03-t");
// svgTest("struct-image-04-t");
// svgTest("struct-image-05-b");
// svgTest("struct-image-06-t");
// svgTest("struct-image-07-t");
// svgTest("struct-image-08-t");
// svgTest("struct-image-09-t");
// svgTest("struct-image-10-t");
// svgTest("struct-symbol-01-b");
// svgTest("struct-use-01-t");
// svgTest("struct-use-03-t");
// svgTest("struct-use-05-b");
// svgTest("styling-css-01-b");
// svgTest("styling-css-02-b");
// svgTest("styling-css-03-b");
// svgTest("styling-css-04-f");
// svgTest("styling-css-05-b");
// svgTest("styling-css-06-b");
// svgTest("styling-inherit-01-b");
// svgTest("styling-pres-01-t");
// svgTest("text-align-01-b");
// svgTest("text-align-02-b");
// svgTest("text-align-03-b");
// svgTest("text-align-04-b");
// svgTest("text-align-05-b");
// svgTest("text-align-06-b");
// svgTest("text-align-08-b");
// svgTest("text-altglyph-01-b");
// svgTest("text-deco-01-b");
// svgTest("text-fonts-01-t");
// svgTest("text-fonts-02-t");
// svgTest("text-fonts-03-t");
// svgTest("text-intro-01-t");
// svgTest("text-intro-02-b");
// svgTest("text-intro-03-b");
// svgTest("text-intro-04-t");
// svgTest("text-intro-05-t");
// svgTest("text-path-01-b");
// svgTest("text-spacing-01-b");
// svgTest("text-text-01-b");
// svgTest("text-text-03-b");
// svgTest("text-text-04-t");
// svgTest("text-text-05-t");
// svgTest("text-text-06-t");
// svgTest("text-text-07-t");
// svgTest("text-text-08-b");
// svgTest("text-tref-01-b");
// svgTest("text-tselect-01-b");
// svgTest("text-tselect-02-f");
// svgTest("text-tspan-01-b");
// svgTest("text-ws-01-t");
// svgTest("text-ws-02-t");
// svgTest("types-basicDOM-01-b");
}
private void applyFillGradients(SvgFill fill, FILLSTYLE fillStyle, RECT bounds, StyleChangeRecord scr, Matrix transform, int shapeNum, SvgStyle style) {
@@ -1453,7 +1452,7 @@ public class SvgImporter {
for (int i = 0; i < gfill.stops.size(); i++) {
SvgStop stop = gfill.stops.get(i);
Color color = stop.color;
color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) Math.round(color.getAlpha() * style.opacity));
color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) Math.round(color.getAlpha() * style.getOpacity()));
fillStyle.gradient.gradientRecords[i] = new GRADRECORD();
fillStyle.gradient.gradientRecords[i].inShape3 = shapeNum >= 3;
fillStyle.gradient.gradientRecords[i].color = getRGB(shapeNum, color);
@@ -1476,7 +1475,7 @@ public class SvgImporter {
private void applyStyleGradients(RECT bounds, StyleChangeRecord scr, Matrix transform, int shapeNum, SvgStyle style) {
SvgFill fill = style.getFillWithOpacity();
if (fill != null) {
if (fill != null && fill != SvgTransparentFill.INSTANCE) {
applyFillGradients(fill, scr.fillStyles.fillStyles[0], bounds, scr, transform, shapeNum, style);
}
SvgFill strokeFill = style.getStrokeFillWithOpacity();
@@ -1495,7 +1494,7 @@ public class SvgImporter {
scr.stateFillStyle1 = true;
scr.stateLineStyle = true;
SvgFill fill = style.getFillWithOpacity();
if (fill != null) {
if (fill != null && fill != SvgTransparentFill.INSTANCE) {
scr.fillStyles.fillStyles = new FILLSTYLE[1];
scr.fillStyles.fillStyles[0] = new FILLSTYLE();
if (fill instanceof SvgColor) {
@@ -1520,9 +1519,9 @@ public class SvgImporter {
scr.lineStyles.lineStyles = new LINESTYLE[1];
LINESTYLE lineStyle = shapeNum <= 3 ? new LINESTYLE() : new LINESTYLE2();
lineStyle.color = getRGB(shapeNum, lineColor);
lineStyle.width = (int) Math.round(style.strokeWidth * SWF.unitDivisor);
SvgLineCap lineCap = style.strokeLineCap;
SvgLineJoin lineJoin = style.strokeLineJoin;
lineStyle.width = (int) Math.round(style.getStrokeWidth() * SWF.unitDivisor);
SvgLineCap lineCap = style.getStrokeLineCap();
SvgLineJoin lineJoin = style.getStrokeLineJoin();
if (lineStyle instanceof LINESTYLE2) {
LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle;
int swfCap = lineCap == SvgLineCap.BUTT ? LINESTYLE2.NO_CAP
@@ -1534,13 +1533,13 @@ public class SvgImporter {
lineStyle2.hasFillFlag = true;
lineStyle2.fillType = new FILLSTYLE();
//...apply in second step - applyStyleGradients
}//Single color does not need fillType attribute
} // Single color does not need fillType attribute
int swfJoin = lineJoin == SvgLineJoin.MITER ? LINESTYLE2.MITER_JOIN
: lineJoin == SvgLineJoin.ROUND ? LINESTYLE2.ROUND_JOIN
: lineJoin == SvgLineJoin.BEVEL ? LINESTYLE2.BEVEL_JOIN : 0;
lineStyle2.joinStyle = swfJoin;
lineStyle2.miterLimitFactor = (float) style.strokeMiterLimit;
lineStyle2.miterLimitFactor = (float) style.getStrokeMiterLimit();
} else {
if (lineCap != SvgLineCap.ROUND) {
showWarning("lineCapNotSupported", "LineCap style not supported in shape " + shapeNum);

View File

@@ -37,61 +37,142 @@ import org.w3c.dom.NodeList;
*
* @author JPEXS
*/
class SvgStyle implements Cloneable {
class SvgStyle {
public Color color;
public SvgFill fill;
public double opacity;
public double fillOpacity;
public SvgFill strokeFill;
public Color stopColor;
public double stopOpacity;
public double strokeWidth;
public double strokeOpacity;
public SvgLineCap strokeLineCap;
public SvgLineJoin strokeLineJoin;
public double strokeMiterLimit;
public SvgStyle parentStyle;
private final Element element;
private final SvgImporter importer;
private final Map<String, Element> idMap;
private final double epsilon = 0.001;
private final Random random = new Random();
public SvgStyle(SvgImporter importer) {
public SvgStyle(SvgImporter importer, Map<String, Element> idMap, Element element) {
this.importer = importer;
fill = new SvgColor(Color.black);
fillOpacity = 1;
strokeFill = null;
strokeWidth = 1;
strokeOpacity = 1;
opacity = 1;
stopOpacity = 1;
stopColor = null;
strokeLineCap = SvgLineCap.BUTT;
strokeLineJoin = SvgLineJoin.MITER;
strokeMiterLimit = 4;
this.idMap = idMap;
this.element = element;
}
public SvgStyle(SvgStyle parentStyle) {
this(parentStyle.importer);
this.parentStyle = parentStyle;
private Map<String, String> getStyleAttributeValues(Element element) {
// todo: cache
Map<String, String> styleValues = new HashMap<>();
if (element.hasAttribute("style")) {
String[] styleDefs = element.getAttribute("style").split(";");
for (String styleDef : styleDefs) {
if (!styleDef.contains(":")) {
continue;
}
String[] parts = styleDef.split(":", 2);
String name = parts[0].trim();
String value = parts[1].trim();
SvgStyleProperty styleProperty = SvgStyleProperty.getByName(name);
if (styleProperty == null) {
importer.showWarning(name + "StyleNotSupported", "The style '" + name + "' is not supported.");
} else {
styleValues.put(name, value);
}
}
}
return styleValues;
}
private <E> E getValue(Element element, String name) {
return getValue(element, name, false);
}
@SuppressWarnings("unchecked")
private <E> E getValue(Element element, String name, boolean inherit) {
Map<String, String> styleValues = getStyleAttributeValues(element);
if (styleValues.containsKey(name)) {
String value = styleValues.get(name);
if ("inherit".equals(value)) {
if (element.getParentNode() instanceof Element) {
return getValue((Element) element.getParentNode(), name, true);
}
} else {
Object result = getStyleValue(this, name, value);
if (result != null) {
return (E) result;
}
}
}
if (element.hasAttribute(name)) {
String value = element.getAttribute(name).trim();
if ("inherit".equals(value)) {
if (element.getParentNode() instanceof Element) {
return getValue((Element) element.getParentNode(), name, true);
}
} else {
Object result = getStyleValue(this, name, value);
if (result != null) {
return (E) result;
}
}
}
SvgStyleProperty p = SvgStyleProperty.getByName(name);
if (inherit || p.isInherited() && element.getParentNode() instanceof Element) {
return getValue((Element) element.getParentNode(), name);
}
return (E) p.getInitialValue();
}
public Color getColor() {
return getValue(element, "color");
}
public SvgFill getFill() {
return getValue(element, "fill");
}
public double getFillOpacity() {
return getValue(element, "fill-opacity");
}
public SvgFill getStroke() {
return getValue(element, "stroke");
}
public double getStrokeWidth() {
return getValue(element, "stroke-width");
}
public double getStrokeOpacity() {
return getValue(element, "stroke-opacity");
}
public SvgLineCap getStrokeLineCap() {
return getValue(element, "stroke-linecap");
}
public SvgLineJoin getStrokeLineJoin() {
return getValue(element, "stroke-linejoin");
}
public double getStrokeMiterLimit() {
return getValue(element, "stroke-miterlimit");
}
public double getOpacity() {
return getValue(element, "opacity");
}
public Color getStopColor() {
return getValue(element, "stop-color");
}
public double getStopOpacity() {
return getValue(element, "stop-opacity");
}
public SvgFill getFillWithOpacity() {
SvgFill fill = getFill();
if (fill == null) {
return null;
}
@@ -100,7 +181,7 @@ class SvgStyle implements Cloneable {
}
Color fillColor = ((SvgColor) fill).color;
int opacity = (int) Math.round(this.opacity * fillOpacity * 255);
int opacity = (int) Math.round(getOpacity() * getFillOpacity() * 255);
if (opacity > 255) {
opacity = 255;
}
@@ -117,6 +198,7 @@ class SvgStyle implements Cloneable {
}
public SvgFill getStrokeFillWithOpacity() {
SvgFill strokeFill = getStroke();
if (strokeFill == null) {
return null;
}
@@ -125,7 +207,7 @@ class SvgStyle implements Cloneable {
}
Color strokeFillColor = ((SvgColor) strokeFill).color;
int opacity = (int) Math.round(this.opacity * strokeOpacity * 255);
int opacity = (int) Math.round(getOpacity() * getStopOpacity() * 255);
if (opacity > 255) {
opacity = 255;
}
@@ -142,6 +224,7 @@ class SvgStyle implements Cloneable {
}
public SvgFill getStrokeColorWithOpacity() {
SvgFill strokeFill = getStroke();
if (strokeFill == null) {
return null;
}
@@ -151,7 +234,7 @@ class SvgStyle implements Cloneable {
Color strokeColor = ((SvgColor) strokeFill).color;
int opacity = (int) Math.round(this.opacity * strokeOpacity * 255);
int opacity = (int) Math.round(getOpacity() * getStrokeOpacity() * 255);
if (opacity == 255) {
return strokeFill;
}
@@ -159,18 +242,8 @@ class SvgStyle implements Cloneable {
return new SvgColor(strokeColor.getRed(), strokeColor.getGreen(), strokeColor.getBlue(), opacity);
}
@Override
public SvgStyle clone() {
try {
SvgStyle ret = (SvgStyle) super.clone();
return ret;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();
}
}
//FIXME - matrices
private SvgFill parseGradient(Map<String, Element> idMap, Element el, SvgStyle style) {
private SvgFill parseGradient(Map<String, Element> idMap, Element el) {
SvgGradientUnits gradientUnits = null;
String gradientTransform = null;
SvgSpreadMethod spreadMethod = null;
@@ -200,7 +273,7 @@ class SvgStyle implements Cloneable {
}
if ("linearGradient".equals(el.getTagName()) && parent_el.getTagName().equals(el.getTagName())) {
SvgLinearGradient parentFill = (SvgLinearGradient) parseGradient(idMap, parent_el, style);
SvgLinearGradient parentFill = (SvgLinearGradient) parseGradient(idMap, parent_el);
gradientUnits = parentFill.gradientUnits;
gradientTransform = parentFill.gradientTransform;
spreadMethod = parentFill.spreadMethod;
@@ -213,7 +286,7 @@ class SvgStyle implements Cloneable {
stops = parentFill.stops;
}
if ("radialGradient".equals(el.getTagName()) && parent_el.getTagName().equals(el.getTagName())) {
SvgRadialGradient parentFill = (SvgRadialGradient) parseGradient(idMap, parent_el, style);
SvgRadialGradient parentFill = (SvgRadialGradient) parseGradient(idMap, parent_el);
gradientUnits = parentFill.gradientUnits;
gradientTransform = parentFill.gradientTransform;
spreadMethod = parentFill.spreadMethod;
@@ -352,7 +425,7 @@ class SvgStyle implements Cloneable {
Node node = stopNodes.item(i);
if (node instanceof Element) {
Element stopEl = (Element) node;
SvgStyle newStyle = style.apply(stopEl, idMap);
SvgStyle newStyle = new SvgStyle(importer, idMap, stopEl);
String offsetStr = stopEl.getAttribute("offset");
double offset;
@@ -361,12 +434,12 @@ class SvgStyle implements Cloneable {
} else {
offset = Double.parseDouble(offsetStr);
}
Color color = newStyle.stopColor;
Color color = newStyle.getStopColor();
if (color == null) {
color = Color.BLACK;
}
int alpha = (int) Math.round(newStyle.stopOpacity * 255);
int alpha = (int) Math.round(newStyle.getStopOpacity() * 255);
color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
if (!stopsCleared) { //It has some stop nodes -> remove all inherited stops
stopsCleared = true;
@@ -436,7 +509,7 @@ class SvgStyle implements Cloneable {
return stops;
}
private SvgFill parseFill(Map<String, Element> idMap, String fillStr, SvgStyle style) {
private SvgFill parseFill(Map<String, Element> idMap, String fillStr) {
if (fillStr == null) {
return null;
}
@@ -454,11 +527,11 @@ class SvgStyle implements Cloneable {
if (e != null) {
String tagName = e.getTagName();
if ("linearGradient".equals(tagName)) {
return parseGradient(idMap, e, new SvgStyle(style)); //? new style
return parseGradient(idMap, e);
}
if ("radialGradient".equals(tagName)) {
return parseGradient(idMap, e, new SvgStyle(style)); //? new style
return parseGradient(idMap, e);
}
if ("pattern".equals(tagName)) {
@@ -513,223 +586,100 @@ class SvgStyle implements Cloneable {
return result;
}
private boolean applyStyle(Map<String, Element> idMap, SvgStyle style, SvgStyle parentStyle, SvgStyleProperty styleProperty, String value) {
boolean inherit = false;
if ("inherit".equals(value)) {
value = "";
inherit = true;
private Object getStyleValue(SvgStyle style, String name, String value) {
if (value == null || value.length() == 0) {
return null;
}
boolean ok = value != null && value.length() != 0;
String name = styleProperty.name();
try {
if (ok) {
ok = false;
switch (name) {
case "color": {
Color color = SvgColor.parse(value).toColor();
if (color != null) {
style.color = color;
ok = true;
}
switch (name) {
case "color": {
Color color = SvgColor.parse(value).toColor();
if (color != null) {
return color;
}
break;
case "fill": {
SvgFill fill = parseFill(idMap, value, style);
}
break;
case "fill": {
if ("currentColor".equals(value)) {
return new SvgColor(style.getColor());
} else {
SvgFill fill = parseFill(idMap, value);
if (fill != null) {
style.fill = fill == SvgTransparentFill.INSTANCE ? null : fill;
ok = true;
return fill;
}
}
break;
case "fill-opacity": {
double opacity = Double.parseDouble(value);
style.fillOpacity = opacity;
ok = true;
}
break;
case "stroke": {
SvgFill strokeFill = parseFill(idMap, value, style);
if (strokeFill != null) {
style.strokeFill = strokeFill == SvgTransparentFill.INSTANCE ? null : strokeFill;
ok = true;
}
break;
case "fill-opacity": {
double opacity = Double.parseDouble(value);
return opacity;
}
case "stroke": {
if ("currentColor".equals(value)) {
return new SvgColor(style.getColor());
} else {
SvgFill stroke = parseFill(idMap, value);
if (stroke != null) {
return stroke;
}
}
break;
case "stroke-width": {
double strokeWidth = Double.parseDouble(value);
style.strokeWidth = strokeWidth;
ok = true;
}
break;
case "stroke-width": {
double strokeWidth = Double.parseDouble(value);
return strokeWidth;
}
case "stroke-opacity": {
double opacity = Double.parseDouble(value);
return opacity;
}
case "stroke-linecap": {
switch (value) {
case "butt":
return SvgLineCap.BUTT;
case "round":
return SvgLineCap.ROUND;
case "square":
return SvgLineCap.SQUARE;
}
break;
case "stroke-opacity": {
double opacity = Double.parseDouble(value);
style.strokeOpacity = opacity;
ok = true;
}
break;
case "stroke-linejoin": {
switch (value) {
case "miter":
return SvgLineJoin.MITER;
case "round":
return SvgLineJoin.ROUND;
case "bevel":
return SvgLineJoin.BEVEL;
}
break;
case "stroke-linecap": {
switch (value) {
case "butt":
style.strokeLineCap = SvgLineCap.BUTT;
ok = true;
break;
case "round":
style.strokeLineCap = SvgLineCap.ROUND;
ok = true;
break;
case "square":
style.strokeLineCap = SvgLineCap.SQUARE;
ok = true;
break;
}
}
break;
case "stroke-miterlimit": {
double strokeMiterLimit = Double.parseDouble(value);
return strokeMiterLimit;
}
case "opacity": {
double opacity = Double.parseDouble(value);
return opacity;
}
case "stop-color": {
if ("currentColor".equals(value)) {
return style.getColor();
} else {
return SvgColor.parse(value).toColor();
}
break;
case "stroke-linejoin": {
switch (value) {
case "miter":
style.strokeLineJoin = SvgLineJoin.MITER;
ok = true;
break;
case "round":
style.strokeLineJoin = SvgLineJoin.ROUND;
ok = true;
break;
case "bevel":
style.strokeLineJoin = SvgLineJoin.BEVEL;
ok = true;
break;
}
}
break;
case "stroke-miterlimit": {
double strokeMiterLimit = Double.parseDouble(value);
style.strokeMiterLimit = strokeMiterLimit;
ok = true;
}
break;
case "opacity": {
double opacity = Double.parseDouble(value);
style.opacity = opacity;
ok = true;
}
break;
case "stop-color": {
if ("currentColor".equals(value)) {
if (style.parentStyle != null) {
style.stopColor = style.parentStyle.color;
}
} else {
//importer.showWarning(value + "StopColorNotSupported", "The stop color value '" + value + "' is not supported.");
style.stopColor = SvgColor.parse(value).toColor();
ok = true;
}
}
break;
case "stop-opacity": {
//importer.showWarning(value + "StopOpacityNotSupported", "The stop opacity value '" + value + "' is not supported.");
double stopOpacity = Double.parseDouble(value);
style.stopOpacity = stopOpacity;
ok = true;
}
break;
}
case "stop-opacity": {
double stopOpacity = Double.parseDouble(value);
return stopOpacity;
}
}
} catch (NumberFormatException ex) {
ok = false;
//ignore
}
if (inherit) {
applyInheritedStyle(style, parentStyle, styleProperty);
ok = true;
}
return ok;
}
private void applyInheritedStyle(SvgStyle style, SvgStyle parentStyle, SvgStyleProperty styleProperty) {
String name = styleProperty.name();
switch (name) {
case "color":
style.color = parentStyle.color;
break;
case "fill":
style.fill = parentStyle.fill;
break;
case "fill-opacity":
style.fillOpacity = parentStyle.opacity;
break;
case "stroke":
style.strokeFill = parentStyle.strokeFill;
break;
case "stroke-width":
style.strokeWidth = parentStyle.strokeWidth;
break;
case "stroke-opacity":
style.strokeOpacity = parentStyle.opacity;
break;
case "stroke-linecap":
style.strokeLineCap = parentStyle.strokeLineCap;
break;
case "stroke-linejoin":
style.strokeLineJoin = parentStyle.strokeLineJoin;
break;
case "stroke-miterlimit":
style.strokeMiterLimit = parentStyle.strokeMiterLimit;
break;
case "opacity":
style.opacity = parentStyle.opacity;
break;
case "stop-color":
style.stopColor = parentStyle.stopColor;
break;
case "stop-opacity":
style.stopOpacity = parentStyle.stopOpacity;
break;
}
}
public SvgStyle apply(Element element, Map<String, Element> idMap) {
SvgStyle result = new SvgStyle(importer);
Map<String, String> styleValues = new HashMap<>();
if (element.hasAttribute("style")) {
String[] styleDefs = element.getAttribute("style").split(";");
for (String styleDef : styleDefs) {
if (!styleDef.contains(":")) {
continue;
}
String[] parts = styleDef.split(":", 2);
String name = parts[0].trim();
String value = parts[1].trim();
SvgStyleProperty styleProperty = SvgStyleProperty.getByName(name);
if (styleProperty == null) {
importer.showWarning(name + "StyleNotSupported", "The style '" + name + "' is not supported.");
} else {
styleValues.put(name, value);
}
}
}
for (SvgStyleProperty styleProperty : SvgStyleProperty.getProperties()) {
String name = styleProperty.name();
boolean ok = false;
if (styleValues.containsKey(name)) {
ok = applyStyle(idMap, result, this, styleProperty, styleValues.get(name));
}
if (!ok && element.hasAttribute(name)) {
String attr = element.getAttribute(name).trim();
ok = applyStyle(idMap, result, this, styleProperty, attr);
}
if (!ok && styleProperty.isInherited()) {
applyInheritedStyle(result, this, styleProperty);
}
}
return result;
return null;
}
}

View File

@@ -16,7 +16,7 @@
*/
package com.jpexs.decompiler.flash.importers.svg;
import com.sun.prism.paint.Color;
import java.awt.Color;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -47,12 +47,16 @@ public class SvgStyleProperty {
return inherited;
}
public Object getInitialValue() {
return initial;
}
private static final Map<String, SvgStyleProperty> properties;
static {
Map<String, SvgStyleProperty> p = new HashMap<>();
p.put("color", new SvgStyleProperty("color", true, null /* depends on user agent */));
p.put("fill", new SvgStyleProperty("fill", true, Color.BLACK));
p.put("color", new SvgStyleProperty("color", true, Color.BLACK /* depends on user agent */));
p.put("fill", new SvgStyleProperty("fill", true, new SvgColor(Color.BLACK)));
p.put("fill-opacity", new SvgStyleProperty("fill-opacity", true, 1.0));
p.put("stroke", new SvgStyleProperty("stroke", true, null));
p.put("stroke-width", new SvgStyleProperty("stroke-width", true, 1.0));