From 27cdd48a1f4d10d84688bd11ae9eec26447ea38e Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Mon, 28 Dec 2015 08:30:16 +0100 Subject: [PATCH] svg style inheritance fix --- .../flash/importers/svg/SvgImporter.java | 401 ++++++++------- .../flash/importers/svg/SvgStyle.java | 478 ++++++++---------- .../flash/importers/svg/SvgStyleProperty.java | 10 +- 3 files changed, 421 insertions(+), 468 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java index 90e0273ff..2f6591da5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java @@ -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); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java index 1d5af35b9..335cb7d6e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java @@ -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 idMap; + private final double epsilon = 0.001; private final Random random = new Random(); - public SvgStyle(SvgImporter importer) { + public SvgStyle(SvgImporter importer, Map 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 getStyleAttributeValues(Element element) { + // todo: cache + Map 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 getValue(Element element, String name) { + return getValue(element, name, false); + } + + @SuppressWarnings("unchecked") + private E getValue(Element element, String name, boolean inherit) { + Map 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 idMap, Element el, SvgStyle style) { + private SvgFill parseGradient(Map 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 idMap, String fillStr, SvgStyle style) { + private SvgFill parseFill(Map 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 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 idMap) { - SvgStyle result = new SvgStyle(importer); - - Map 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; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyleProperty.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyleProperty.java index 13fc60344..1bfd67ac2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyleProperty.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyleProperty.java @@ -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 properties; static { Map 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));