Skip to content

Commit cb31640

Browse files
committed
Add SVG symbol processing by adding SymbolSvgNodeRenderer
* Add AbstractContainerSvgNodeRenderer class * Add INoDrawSvgNodeRenderer interface * Update unit tests * Add minor code style improvements DEVSIX-2257
1 parent cc64368 commit cb31640

File tree

56 files changed

+289
-271
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+289
-271
lines changed

svg/src/main/java/com/itextpdf/svg/exceptions/SvgLogMessageConstant.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public final class SvgLogMessageConstant {
5151
public static final String ATTRIBUTES_NULL = "The attributes of this element are null.";
5252
public static final String COORDINATE_VALUE_ABSENT = "The coordinate value is empty or null.";
5353
public static final String COULDNOTINSTANTIATE = "Could not instantiate Renderer for tag {0}";
54-
public static final String DRAW_NO_DRAW = "Can't draw a NoDrawOperationSvgNodeRenderer.";
54+
public static final String DRAW_NO_DRAW = "Can't draw current SvgNodeRenderer.";
5555
@Deprecated
5656
public static final String ERROR_CLOSING_CSS_STREAM = "An error occured when trying to close the InputStream of the default CSS.";
5757
public static final String ERROR_INITIALIZING_DEFAULT_CSS = "Error loading the default CSS. Initializing an empty style sheet.";

svg/src/main/java/com/itextpdf/svg/processors/impl/DefaultSvgProcessor.java

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,14 @@ This file is part of the iText (R) project.
5757
import com.itextpdf.svg.processors.ISvgProcessorResult;
5858
import com.itextpdf.svg.processors.impl.font.SvgFontProcessor;
5959
import com.itextpdf.svg.renderers.IBranchSvgNodeRenderer;
60+
import com.itextpdf.svg.renderers.INoDrawSvgNodeRenderer;
6061
import com.itextpdf.svg.renderers.ISvgNodeRenderer;
6162
import com.itextpdf.svg.renderers.factories.DefaultSvgNodeRendererFactory;
6263
import com.itextpdf.svg.renderers.factories.ISvgNodeRendererFactory;
64+
import com.itextpdf.svg.renderers.impl.DefsSvgNodeRenderer;
6365
import com.itextpdf.svg.renderers.impl.ISvgTextNodeRenderer;
64-
import com.itextpdf.svg.renderers.impl.NoDrawOperationSvgNodeRenderer;
66+
import com.itextpdf.svg.renderers.impl.LinearGradientSvgNodeRenderer;
67+
import com.itextpdf.svg.renderers.impl.StopSvgNodeRenderer;
6568
import com.itextpdf.svg.renderers.impl.TextLeafSvgNodeRenderer;
6669
import com.itextpdf.svg.renderers.impl.TextSvgBranchRenderer;
6770
import com.itextpdf.svg.utils.SvgTextUtil;
@@ -189,7 +192,7 @@ private void visit(INode node) {
189192

190193
if (!rendererFactory.isTagIgnored(element)) {
191194
ISvgNodeRenderer parentRenderer = processorState.top();
192-
ISvgNodeRenderer renderer = createRenderer(element, parentRenderer);
195+
ISvgNodeRenderer renderer = rendererFactory.createSvgNodeRendererForTag(element, parentRenderer);
193196
if (renderer != null) {
194197
Map<String, String> styles;
195198
if (cssResolver instanceof SvgStyleResolver
@@ -208,17 +211,19 @@ && onlyNativeStylesShouldBeResolved(element)) {
208211
namedObjects.put(attribute, renderer);
209212
}
210213

211-
if (renderer instanceof NoDrawOperationSvgNodeRenderer) {
212-
// add the NoDrawOperationSvgNodeRenderer or its subtree to the ISvgNodeRenderer tree
213-
// only if the parent is NoDrawOperationSvgNodeRenderer itself
214-
if (parentRenderer instanceof NoDrawOperationSvgNodeRenderer) {
215-
((NoDrawOperationSvgNodeRenderer) parentRenderer).addChild(renderer);
214+
if (renderer instanceof StopSvgNodeRenderer) {
215+
if (parentRenderer instanceof LinearGradientSvgNodeRenderer) {
216+
// It is necessary to add StopSvgNodeRenderer only as a child of LinearGradientSvgNodeRenderer,
217+
// because StopSvgNodeRenderer performs an auxiliary function and should not be drawn at all
218+
((LinearGradientSvgNodeRenderer) parentRenderer).addChild(renderer);
216219
}
217-
} else {
220+
}
221+
// DefsSvgNodeRenderer should not have parental relationship with any renderer, it only serves as a storage
222+
else if (!(renderer instanceof INoDrawSvgNodeRenderer) && !(parentRenderer instanceof DefsSvgNodeRenderer)) {
218223
if (parentRenderer instanceof IBranchSvgNodeRenderer) {
219224
((IBranchSvgNodeRenderer) parentRenderer).addChild(renderer);
220225
} else if (parentRenderer instanceof TextSvgBranchRenderer && renderer instanceof ISvgTextNodeRenderer) {
221-
//Text branch node renderers only accept ISvgTextNodeRenderers
226+
// Text branch node renderers only accept ISvgTextNodeRenderers
222227
((TextSvgBranchRenderer) parentRenderer).addChild((ISvgTextNodeRenderer) renderer);
223228
}
224229
}
@@ -260,17 +265,6 @@ private static boolean isElementNested(IElementNode element, String parentElemen
260265
return false;
261266
}
262267

263-
/**
264-
* Create renderer based on the passed SVG tag and assign its parent
265-
*
266-
* @param tag SVG tag with all style attributes already assigned
267-
* @param parent renderer of the parent tag
268-
* @return Configured renderer for the tag
269-
*/
270-
private ISvgNodeRenderer createRenderer(IElementNode tag, ISvgNodeRenderer parent) {
271-
return rendererFactory.createSvgNodeRendererForTag(tag, parent);
272-
}
273-
274268
/**
275269
* Check if this node is a text node that needs to be processed by the parent
276270
*
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2020 iText Group NV
4+
Authors: iText Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
package com.itextpdf.svg.renderers;
24+
25+
/**
26+
* Interface that defines branches in the NodeRenderer structure that will not draw on its own.
27+
*/
28+
public interface INoDrawSvgNodeRenderer extends IBranchSvgNodeRenderer {
29+
}

svg/src/main/java/com/itextpdf/svg/renderers/factories/DefaultSvgNodeRendererFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ This file is part of the iText (R) project.
4646
import com.itextpdf.styledxmlparser.node.IElementNode;
4747
import com.itextpdf.svg.exceptions.SvgLogMessageConstant;
4848
import com.itextpdf.svg.exceptions.SvgProcessingException;
49+
import com.itextpdf.svg.renderers.INoDrawSvgNodeRenderer;
4950
import com.itextpdf.svg.renderers.ISvgNodeRenderer;
50-
import com.itextpdf.svg.renderers.impl.NoDrawOperationSvgNodeRenderer;
51+
import com.itextpdf.svg.renderers.impl.DefsSvgNodeRenderer;
5152

5253
import java.util.Collection;
5354
import java.util.HashMap;
@@ -117,7 +118,8 @@ public ISvgNodeRenderer createSvgNodeRendererForTag(IElementNode tag, ISvgNodeRe
117118
throw new SvgProcessingException(SvgLogMessageConstant.COULDNOTINSTANTIATE, ex).setMessageParams(tag.name());
118119
}
119120

120-
if (parent != null && !(parent instanceof NoDrawOperationSvgNodeRenderer)) {
121+
// DefsSvgNodeRenderer should not have parental relationship with any renderer, it only serves as a storage
122+
if (parent != null && !(result instanceof INoDrawSvgNodeRenderer) && !(parent instanceof DefsSvgNodeRenderer)) {
121123
result.setParent(parent);
122124
}
123125

svg/src/main/java/com/itextpdf/svg/renderers/factories/DefaultSvgNodeRendererMapper.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,21 @@ This file is part of the iText (R) project.
4545
import com.itextpdf.svg.SvgConstants;
4646
import com.itextpdf.svg.renderers.ISvgNodeRenderer;
4747
import com.itextpdf.svg.renderers.impl.ClipPathSvgNodeRenderer;
48+
import com.itextpdf.svg.renderers.impl.DefsSvgNodeRenderer;
4849
import com.itextpdf.svg.renderers.impl.GroupSvgNodeRenderer;
4950
import com.itextpdf.svg.renderers.impl.CircleSvgNodeRenderer;
5051
import com.itextpdf.svg.renderers.impl.EllipseSvgNodeRenderer;
5152
import com.itextpdf.svg.renderers.impl.ImageSvgNodeRenderer;
5253
import com.itextpdf.svg.renderers.impl.LineSvgNodeRenderer;
5354
import com.itextpdf.svg.renderers.impl.LinearGradientSvgNodeRenderer;
5455
import com.itextpdf.svg.renderers.impl.MarkerSvgNodeRenderer;
55-
import com.itextpdf.svg.renderers.impl.NoDrawOperationSvgNodeRenderer;
5656
import com.itextpdf.svg.renderers.impl.PathSvgNodeRenderer;
5757
import com.itextpdf.svg.renderers.impl.PolygonSvgNodeRenderer;
5858
import com.itextpdf.svg.renderers.impl.PolylineSvgNodeRenderer;
5959
import com.itextpdf.svg.renderers.impl.RectangleSvgNodeRenderer;
6060
import com.itextpdf.svg.renderers.impl.StopSvgNodeRenderer;
6161
import com.itextpdf.svg.renderers.impl.SvgTagSvgNodeRenderer;
62+
import com.itextpdf.svg.renderers.impl.SymbolSvgNodeRenderer;
6263
import com.itextpdf.svg.renderers.impl.TextSvgBranchRenderer;
6364
import com.itextpdf.svg.renderers.impl.TextSvgTSpanBranchRenderer;
6465
import com.itextpdf.svg.renderers.impl.UseSvgNodeRenderer;
@@ -89,7 +90,7 @@ public Map<String, Class<? extends ISvgNodeRenderer>> getMapping() {
8990

9091
result.put(SvgConstants.Tags.CIRCLE, CircleSvgNodeRenderer.class);
9192
result.put(SvgConstants.Tags.CLIP_PATH, ClipPathSvgNodeRenderer.class);
92-
result.put(SvgConstants.Tags.DEFS, NoDrawOperationSvgNodeRenderer.class);
93+
result.put(SvgConstants.Tags.DEFS, DefsSvgNodeRenderer.class);
9394
result.put(SvgConstants.Tags.ELLIPSE, EllipseSvgNodeRenderer.class);
9495
result.put(SvgConstants.Tags.G, GroupSvgNodeRenderer.class);
9596
result.put(SvgConstants.Tags.IMAGE, ImageSvgNodeRenderer.class);
@@ -102,6 +103,7 @@ public Map<String, Class<? extends ISvgNodeRenderer>> getMapping() {
102103
result.put(SvgConstants.Tags.RECT, RectangleSvgNodeRenderer.class);
103104
result.put(SvgConstants.Tags.STOP, StopSvgNodeRenderer.class);
104105
result.put(SvgConstants.Tags.SVG, SvgTagSvgNodeRenderer.class);
106+
result.put(SvgConstants.Tags.SYMBOL, SymbolSvgNodeRenderer.class);
105107
result.put(SvgConstants.Tags.TEXT, TextSvgBranchRenderer.class);
106108
result.put(SvgConstants.Tags.TSPAN, TextSvgTSpanBranchRenderer.class);
107109
result.put(SvgConstants.Tags.USE, UseSvgNodeRenderer.class);

svg/src/main/java/com/itextpdf/svg/renderers/impl/AbstractBranchSvgNodeRenderer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ This file is part of the iText (R) project.
6767
import java.util.Arrays;
6868
import java.util.Collections;
6969
import java.util.List;
70+
7071
import org.slf4j.Logger;
7172
import org.slf4j.LoggerFactory;
7273

@@ -87,7 +88,7 @@ public abstract class AbstractBranchSvgNodeRenderer extends AbstractSvgNodeRende
8788
*/
8889
@Override
8990
protected void doDraw(SvgDrawContext context) {
90-
// if branch has no children, don't do anything
91+
// If branch has no children, don't do anything
9192
if (getChildren().size() > 0) {
9293
PdfStream stream = new PdfStream();
9394
stream.put(PdfName.Type, PdfName.XObject);
@@ -130,7 +131,7 @@ protected void doDraw(SvgDrawContext context) {
130131

131132
cleanUp(context);
132133

133-
// transformation already happened in AbstractSvgNodeRenderer, so no need to do a transformation here
134+
// Transformation already happened in AbstractSvgNodeRenderer, so no need to do a transformation here
134135
context.getCurrentCanvas().addXObject(xObject, 0, 0);
135136
}
136137
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2020 iText Group NV
4+
Authors: iText Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
package com.itextpdf.svg.renderers.impl;
24+
25+
import com.itextpdf.kernel.geom.Rectangle;
26+
import com.itextpdf.styledxmlparser.css.CommonCssConstants;
27+
import com.itextpdf.styledxmlparser.css.resolve.CssDefaults;
28+
import com.itextpdf.styledxmlparser.css.util.CssUtils;
29+
import com.itextpdf.svg.SvgConstants;
30+
import com.itextpdf.svg.renderers.SvgDrawContext;
31+
32+
public abstract class AbstractContainerSvgNodeRenderer extends AbstractBranchSvgNodeRenderer {
33+
@Override
34+
public float getCurrentFontSize() {
35+
String fontSizeValue = getAttribute(SvgConstants.Attributes.FONT_SIZE);
36+
if (fontSizeValue == null) {
37+
fontSizeValue = CssDefaults.getDefaultValue(CommonCssConstants.FONT_SIZE);
38+
}
39+
return CssUtils.parseAbsoluteFontSize(fontSizeValue);
40+
}
41+
42+
@Override
43+
public boolean canConstructViewPort(){ return true;}
44+
45+
@Override
46+
protected boolean canElementFill() {
47+
return false;
48+
}
49+
50+
@Override
51+
protected void doDraw(SvgDrawContext context) {
52+
context.addViewPort(this.calculateViewPort(context));
53+
super.doDraw(context);
54+
}
55+
56+
/**
57+
* Calculate the viewport based on the context.
58+
*
59+
* @param context the SVG draw context
60+
* @return the viewport that applies to this renderer
61+
*/
62+
Rectangle calculateViewPort(SvgDrawContext context) {
63+
Rectangle currentViewPort = context.getCurrentViewPort();
64+
65+
// Set default values to parent viewport in the case of a nested svg tag
66+
float portX = currentViewPort.getX();
67+
float portY = currentViewPort.getY();
68+
// Default should be parent portWidth if not outermost
69+
float portWidth = currentViewPort.getWidth();
70+
// Default should be parent height if not outermost
71+
float portHeight = currentViewPort.getHeight();
72+
73+
74+
if (attributesAndStyles != null) {
75+
if (attributesAndStyles.containsKey(SvgConstants.Attributes.X)) {
76+
portX = CssUtils.parseAbsoluteLength(attributesAndStyles.get(SvgConstants.Attributes.X));
77+
}
78+
if (attributesAndStyles.containsKey(SvgConstants.Attributes.Y)) {
79+
portY = CssUtils.parseAbsoluteLength(attributesAndStyles.get(SvgConstants.Attributes.Y));
80+
}
81+
if (attributesAndStyles.containsKey(SvgConstants.Attributes.WIDTH)) {
82+
portWidth = CssUtils.parseAbsoluteLength(attributesAndStyles.get(SvgConstants.Attributes.WIDTH));
83+
}
84+
if (attributesAndStyles.containsKey(SvgConstants.Attributes.HEIGHT)) {
85+
portHeight = CssUtils.parseAbsoluteLength(attributesAndStyles.get(SvgConstants.Attributes.HEIGHT));
86+
}
87+
}
88+
89+
return new Rectangle(portX, portY, portWidth, portHeight);
90+
}
91+
}

svg/src/main/java/com/itextpdf/svg/renderers/impl/AbstractGradientSvgNodeRenderer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ This file is part of the iText (R) project.
3434
import com.itextpdf.svg.renderers.SvgDrawContext;
3535
import com.itextpdf.svg.utils.TransformUtils;
3636

37+
import org.slf4j.LoggerFactory;
38+
3739
import java.util.ArrayList;
3840
import java.util.List;
39-
import org.slf4j.LoggerFactory;
4041

4142
/**
4243
* {@link ISvgNodeRenderer} abstract implementation for gradient tags

svg/src/main/java/com/itextpdf/svg/renderers/impl/CircleSvgNodeRenderer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public class CircleSvgNodeRenderer extends EllipseSvgNodeRenderer {
5555

5656
@Override
5757
protected boolean setParameters(){
58-
cx=0; cy=0;
58+
cx = 0;
59+
cy = 0;
5960
if(getAttribute(SvgConstants.Attributes.CX) != null){
6061
cx = CssUtils.parseAbsoluteLength(getAttribute(SvgConstants.Attributes.CX));
6162
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2020 iText Group NV
4+
Authors: iText Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
package com.itextpdf.svg.renderers.impl;
24+
25+
import com.itextpdf.svg.exceptions.SvgLogMessageConstant;
26+
import com.itextpdf.svg.renderers.INoDrawSvgNodeRenderer;
27+
import com.itextpdf.svg.renderers.ISvgNodeRenderer;
28+
import com.itextpdf.svg.renderers.SvgDrawContext;
29+
30+
public class DefsSvgNodeRenderer extends AbstractBranchSvgNodeRenderer implements INoDrawSvgNodeRenderer {
31+
@Override
32+
protected void doDraw(SvgDrawContext context) {
33+
throw new UnsupportedOperationException(SvgLogMessageConstant.DRAW_NO_DRAW);
34+
}
35+
36+
@Override
37+
public ISvgNodeRenderer createDeepCopy() {
38+
DefsSvgNodeRenderer copy = new DefsSvgNodeRenderer();
39+
deepCopyAttributesAndStyles(copy);
40+
return copy;
41+
}
42+
}

0 commit comments

Comments
 (0)