/*
GNU GENERAL LICENSE
Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
verion 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General License for more details.
You should have received a copy of the GNU General Public
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it
*/
package org.lobobrowser.html.control;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import org.lobobrowser.html.domimpl.HTMLElementImpl;
import org.lobobrowser.html.info.SVGInfo;
import org.lobobrowser.html.style.AbstractCSS2Properties;
import org.lobobrowser.html.style.HtmlValues;
import org.lobobrowser.html.svgimpl.SVGCircleElementImpl;
import org.lobobrowser.html.svgimpl.SVGEllipseElementImpl;
import org.lobobrowser.html.svgimpl.SVGGElementImpl;
import org.lobobrowser.html.svgimpl.SVGLengthImpl;
import org.lobobrowser.html.svgimpl.SVGLineElementImpl;
import org.lobobrowser.html.svgimpl.SVGMatrixImpl;
import org.lobobrowser.html.svgimpl.SVGPathElementImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegArcAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegArcRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoCubicAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoCubicRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoCubicSmoothAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoCubicSmoothRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoQuadraticAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoQuadraticRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoQuadraticSmoothAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegCurvetoQuadraticSmoothRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegLinetoAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegLinetoHorizontalAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegLinetoHorizontalRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegLinetoRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegLinetoVerticalAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegLinetoVerticalRelImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegMovetoAbsImpl;
import org.lobobrowser.html.svgimpl.SVGPathSegMovetoRelImpl;
import org.lobobrowser.html.svgimpl.SVGPointImpl;
import org.lobobrowser.html.svgimpl.SVGPolygonElementImpl;
import org.lobobrowser.html.svgimpl.SVGPolylineElementImpl;
import org.lobobrowser.html.svgimpl.SVGRectElementImpl;
import org.lobobrowser.html.svgimpl.SVGSVGElementImpl;
import org.lobobrowser.html.svgimpl.SVGUseElementImpl;
import org.lobobrowser.html.svgimpl.SVGUtility;
import org.lobobrowser.util.gui.ColorFactory;
import org.lobobrowser.w3c.svg.SVGLengthList;
import org.lobobrowser.w3c.svg.SVGPathSegList;
import org.lobobrowser.w3c.svg.SVGPoint;
import org.lobobrowser.w3c.svg.SVGPointList;
import org.lobobrowser.w3c.svg.SVGTransform;
import org.lobobrowser.w3c.svg.SVGTransformList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.svg.SVGPathSeg;
public class SVGBasicControl extends BaseControl {
private static final long serialVersionUID = 1L;
private SVGInfo svgiGroup = new SVGInfo();
/** The circle. */
public final int CIRCLE = 1;
/** The rect. */
public final int RECT = 2;
/** The ellipse. */
public final int ELLIPSE = 3;
/** The line. */
public final int LINE = 4;
/** The line. */
public final int POLYGON = 5;
/** The line. */
public final int POLYLINE = 6;
/** The path. */
public final int PATH = 7;
/** The use. */
public final int USE = 8;
/** The text. */
public final int TEXT = 9;
public SVGBasicControl(HTMLElementImpl modelNode) {
super(modelNode);
}
public void circle(Graphics2D g2d, SVGInfo svgi) {
Shape circle = new Ellipse2D.Double(svgi.getX() - svgi.getR(), svgi.getY() - svgi.getR(), 2 * svgi.getR(), 2 * svgi.getR());
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, circle, svgi);
}
public void rectangle(Graphics2D g2d, SVGInfo svgi) {
Shape rect;
if (svgi.getRx() > 0 || svgi.getRy() > 0) {
if (svgi.getRx() > 0 && svgi.getRy() == 0) {
svgi.setRy(svgi.getRx());
} else if (svgi.getRx() == 0 && svgi.getRy() > 0) {
svgi.setRx(svgi.getRy());
}
rect = new RoundRectangle2D.Float(svgi.getX(), svgi.getY(), svgi.getWidth(), svgi.getHeight(),
svgi.getRx() * 2, svgi.getRy() * 2);
} else {
rect = new Rectangle2D.Float(svgi.getX(), svgi.getY(), svgi.getWidth(), svgi.getHeight());
}
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, rect, svgi);
}
public void ellipse(Graphics2D g2d, SVGInfo svgi) {
Point2D.Float center = convertCoordinate(new Point2D.Float(svgi.getX(), svgi.getY()));
Point2D.Float corner = convertCoordinate(new Point2D.Float(svgi.getX() - svgi.getRx(), svgi.getY() - svgi.getRy()));
Ellipse2D.Float ellipse2d = new Ellipse2D.Float();
ellipse2d.setFrameFromCenter(center, corner);
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, ellipse2d, svgi);
}
public void line(Graphics2D g2d, SVGInfo svgi) {
Point2D.Float p = new Point2D.Float(svgi.getX1(), svgi.getY1());
Point2D.Float p1 = convertCoordinate(p);
p = new Point2D.Float(svgi.getX2(), svgi.getY2());
Point2D.Float p2 = convertCoordinate(p);
Line2D line2d = new Line2D.Float(p1, p2);
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, line2d, svgi);
}
public void polygon(Graphics2D g2d, SVGInfo svgi) {
GeneralPath path = new GeneralPath();
SVGPointList points = svgi.getPoilist();
int numPoints = points.getNumberOfItems();
for (int i = 0; i < numPoints; i++) {
SVGPoint point = points.getItem(i);
float x = point.getX();
float y = point.getY();
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
path.closePath();
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, path, svgi);
}
public void polyline(Graphics2D g2d, SVGInfo svgi) {
GeneralPath path = new GeneralPath();
SVGPointList points = svgi.getPoilist();
int numPoints = points.getNumberOfItems();
for (int i = 0; i < numPoints; i++) {
SVGPoint point = points.getItem(i);
float x = point.getX();
float y = point.getY();
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
path.closePath();
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, path, svgi);
}
public void path(Graphics2D g2d, SVGInfo svgi) {
GeneralPath path = new GeneralPath();
Point2D lastControlPoint = null;
SVGPoint subPathStartPoint = null;
SVGPathSegList list = svgi.getPathSegList();
boolean startOfSubPath = true;
int numPathSegs = list.getNumberOfItems();
float lastX = 0;
float lastY = 0;
for (int i = 0; i < numPathSegs; i++) {
SVGPathSegImpl seg = (SVGPathSegImpl) list.getItem(i);
if (startOfSubPath) {
while (!seg.getPathSegTypeAsLetter().equalsIgnoreCase("m") && i < numPathSegs) {
i++;
seg = (SVGPathSegImpl) list.getItem(i);
}
if (seg.getPathSegTypeAsLetter().equalsIgnoreCase("m")) {
if (seg.getPathSegType() == SVGPathSeg.PATHSEG_MOVETO_REL) {
float x = ((SVGPathSegMovetoRelImpl) seg).getX();
float y = ((SVGPathSegMovetoRelImpl) seg).getY();
path.moveTo(x + lastX, y + lastY);
subPathStartPoint = new SVGPointImpl(x + lastX, y + lastY);
lastX += x;
lastY += y;
} else if (seg.getPathSegType() == SVGPathSeg.PATHSEG_MOVETO_ABS) {
float x = ((SVGPathSegMovetoAbsImpl) seg).getX();
float y = ((SVGPathSegMovetoAbsImpl) seg).getY();
path.moveTo(x, y);
subPathStartPoint = new SVGPointImpl(x, y);
lastX = x;
lastY = y;
}
startOfSubPath = false;
}
} else {
switch (seg.getPathSegType()) {
case SVGPathSeg.PATHSEG_CLOSEPATH: {
path.closePath();
lastControlPoint = null;
startOfSubPath = true;
if (subPathStartPoint != null) {
lastX = subPathStartPoint.getX();
lastY = subPathStartPoint.getY();
subPathStartPoint = null;
}
break;
}
case SVGPathSeg.PATHSEG_MOVETO_ABS: {
float x = ((SVGPathSegMovetoAbsImpl) seg).getX();
float y = ((SVGPathSegMovetoAbsImpl) seg).getY();
path.moveTo(x, y);
lastX = x;
lastY = y;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_MOVETO_REL: {
float x = ((SVGPathSegMovetoRelImpl) seg).getX();
float y = ((SVGPathSegMovetoRelImpl) seg).getY();
path.moveTo(x + lastX, y + lastY);
lastX += x;
lastY += y;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_LINETO_ABS: {
float x = ((SVGPathSegLinetoAbsImpl) seg).getX();
float y = ((SVGPathSegLinetoAbsImpl) seg).getY();
path.lineTo(x, y);
lastX = x;
lastY = y;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_LINETO_REL: {
float x = ((SVGPathSegLinetoRelImpl) seg).getX();
float y = ((SVGPathSegLinetoRelImpl) seg).getY();
path.lineTo(x + lastX, y + lastY);
lastX += x;
lastY += y;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: {
float x = ((SVGPathSegLinetoHorizontalAbsImpl) seg).getX();
path.lineTo(x, lastY);
lastX = x;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: {
float x = ((SVGPathSegLinetoHorizontalRelImpl) seg).getX();
path.lineTo(x + lastX, lastY);
lastX += x;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: {
float y = ((SVGPathSegLinetoVerticalAbsImpl) seg).getY();
path.lineTo(lastX, y);
lastY = y;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: {
float y = ((SVGPathSegLinetoVerticalRelImpl) seg).getY();
path.lineTo(lastX, y + lastY);
lastY += y;
lastControlPoint = null;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: {
float x = ((SVGPathSegCurvetoCubicAbsImpl) seg).getX();
float y = ((SVGPathSegCurvetoCubicAbsImpl) seg).getY();
float x1 = ((SVGPathSegCurvetoCubicAbsImpl) seg).getX1();
float y1 = ((SVGPathSegCurvetoCubicAbsImpl) seg).getY1();
float x2 = ((SVGPathSegCurvetoCubicAbsImpl) seg).getX2();
float y2 = ((SVGPathSegCurvetoCubicAbsImpl) seg).getY2();
path.curveTo(x1, y1, x2, y2, x, y);
lastControlPoint = new Point2D.Float(x2, y2);
lastX = x;
lastY = y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: {
float x = ((SVGPathSegCurvetoCubicRelImpl) seg).getX();
float y = ((SVGPathSegCurvetoCubicRelImpl) seg).getY();
float x1 = ((SVGPathSegCurvetoCubicRelImpl) seg).getX1();
float y1 = ((SVGPathSegCurvetoCubicRelImpl) seg).getY1();
float x2 = ((SVGPathSegCurvetoCubicRelImpl) seg).getX2();
float y2 = ((SVGPathSegCurvetoCubicRelImpl) seg).getY2();
path.curveTo(lastX + x1, lastY + y1, lastX + x2, lastY + y2, lastX + x, lastY + y);
lastControlPoint = new Point2D.Float(lastX + x2, lastY + y2);
lastX += x;
lastY += y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: {
float x = ((SVGPathSegCurvetoCubicSmoothAbsImpl) seg).getX();
float y = ((SVGPathSegCurvetoCubicSmoothAbsImpl) seg).getY();
float x2 = ((SVGPathSegCurvetoCubicSmoothAbsImpl) seg).getX2();
float y2 = ((SVGPathSegCurvetoCubicSmoothAbsImpl) seg).getY2();
if (lastControlPoint == null)
lastControlPoint = new Point2D.Float(lastX, lastY);
path.curveTo(2 * lastX - (float) lastControlPoint.getX(), 2 * lastY - (float) lastControlPoint.getY(), x2, y2, x, y);
lastControlPoint = new Point2D.Float(x2, y2);
lastX = x;
lastY = y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: {
float x = ((SVGPathSegCurvetoCubicSmoothRelImpl) seg).getX();
float y = ((SVGPathSegCurvetoCubicSmoothRelImpl) seg).getY();
float x2 = ((SVGPathSegCurvetoCubicSmoothRelImpl) seg).getX2();
float y2 = ((SVGPathSegCurvetoCubicSmoothRelImpl) seg).getY2();
if (lastControlPoint == null)
lastControlPoint = new Point2D.Float(lastX, lastY);
path.curveTo(2 * lastX - (float) lastControlPoint.getX(), 2 * lastY - (float) lastControlPoint.getY(), lastX + x2, lastY + y2, lastX + x, lastY + y);
lastControlPoint = new Point2D.Float(lastX + x2, lastY + y2);
lastX += x;
lastY += y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: {
float x = ((SVGPathSegCurvetoQuadraticAbsImpl) seg).getX();
float y = ((SVGPathSegCurvetoQuadraticAbsImpl) seg).getY();
float x1 = ((SVGPathSegCurvetoQuadraticAbsImpl) seg).getX1();
float y1 = ((SVGPathSegCurvetoQuadraticAbsImpl) seg).getY1();
path.quadTo(x1, y1, x, y);
lastControlPoint = new Point2D.Float(x1, y1);
lastX = x;
lastY = y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: {
float x = ((SVGPathSegCurvetoQuadraticRelImpl) seg).getX();
float y = ((SVGPathSegCurvetoQuadraticRelImpl) seg).getY();
float x1 = ((SVGPathSegCurvetoQuadraticRelImpl) seg).getX1();
float y1 = ((SVGPathSegCurvetoQuadraticRelImpl) seg).getY1();
path.quadTo(lastX + x1, lastY + y1, lastX + x, lastY + y);
lastControlPoint = new Point2D.Float(lastX + x1, lastY + y1);
lastX += x;
lastY += y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: {
float x = ((SVGPathSegCurvetoQuadraticSmoothAbsImpl) seg).getX();
float y = ((SVGPathSegCurvetoQuadraticSmoothAbsImpl) seg).getY();
if (lastControlPoint == null)
lastControlPoint = new Point2D.Float(lastX, lastY);
Point2D nextControlPoint = new Point2D.Float(2 * lastX - (float) lastControlPoint.getX(), 2 * lastY - (float) lastControlPoint.getY());
path.quadTo((float) nextControlPoint.getX(), (float) nextControlPoint.getY(), x, y);
lastControlPoint = nextControlPoint;
lastX = x;
lastY = y;
break;
}
case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: {
float x = ((SVGPathSegCurvetoQuadraticSmoothRelImpl) seg).getX();
float y = ((SVGPathSegCurvetoQuadraticSmoothRelImpl) seg).getY();
if (lastControlPoint == null)
lastControlPoint = new Point2D.Float(lastX, lastY);
Point2D nextControlPoint = new Point2D.Float(2 * lastX - (float) lastControlPoint.getX(), 2 * lastY - (float) lastControlPoint.getY());
path.quadTo((float) nextControlPoint.getX(), (float) nextControlPoint.getY(), lastX + x, lastY + y);
lastControlPoint = nextControlPoint;
lastX += x;
lastY += y;
break;
}
case SVGPathSeg.PATHSEG_ARC_ABS: {
float x1 = lastX;
float y1 = lastY;
float x2 = ((SVGPathSegArcAbsImpl) seg).getX();
float y2 = ((SVGPathSegArcAbsImpl) seg).getY();
float rx = Math.abs(((SVGPathSegArcAbsImpl) seg).getR1());
float ry = Math.abs(((SVGPathSegArcAbsImpl) seg).getR2());
float angle = (float) Math.toRadians(((SVGPathSegArcAbsImpl) seg).getAngle());
boolean fA = ((SVGPathSegArcAbsImpl) seg).getLargeArcFlag();
boolean fS = ((SVGPathSegArcAbsImpl) seg).getSweepFlag();
if (rx == 0 || ry == 0) {
// radii 0, just do a lineTo
path.lineTo(x2, y2);
lastX = x2;
lastY = y2;
lastControlPoint = null;
} else {
Shape arc = createArc(x1, y1, x2, y2, rx, ry, angle, fA, fS);
path.append(arc, true);
lastX = x2;
lastY = y2;
lastControlPoint = null;
}
break;
}
case SVGPathSeg.PATHSEG_ARC_REL: {
float x1 = lastX;
float y1 = lastY;
float x2 = lastX + ((SVGPathSegArcRelImpl) seg).getX();
float y2 = lastY + ((SVGPathSegArcRelImpl) seg).getY();
float rx = Math.abs(((SVGPathSegArcRelImpl) seg).getR1());
float ry = Math.abs(((SVGPathSegArcRelImpl) seg).getR2());
float angle = (float) Math.toRadians(((SVGPathSegArcRelImpl) seg).getAngle());
boolean fA = ((SVGPathSegArcRelImpl) seg).getLargeArcFlag();
boolean fS = ((SVGPathSegArcRelImpl) seg).getSweepFlag();
if (rx == 0 || ry == 0) {
// radii 0, just do a lineTo
path.lineTo(x2, y2);
lastX = x2;
lastY = y2;
lastControlPoint = null;
} else {
Shape arc = createArc(x1, y1, x2, y2, rx, ry, angle, fA, fS);
path.append(arc, true);
lastX = x2;
lastY = y2;
}
break;
}
}
}
}
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, path, svgi);
}
public void use(Graphics2D g2d, SVGInfo svgi,SVGSVGElementImpl svg) {
String href = svgi.getHref();
float x = svgi.getX();
float y = svgi.getY();
AbstractCSS2Properties style = svgi.getStyle();
SVGTransformList transformList = svgi.getTransformList();
Element elementById = svg.getOwnerDocument().getElementById(href.split("#")[1]);
ArrayList<SVGInfo> useList = useChildren(elementById);
for (int i = 0; i < useList.size(); i++) {
SVGInfo info = useList.get(i);
if (x > 0) {
info.setX(x);
}
if (y > 0) {
info.setY(y);
}
if(style != null){
info.setStyle(style);
}
if(transformList!= null && transformList.getNumberOfItems() > 0){
info.setTransformList(transformList);
}
switch (info.getMethod()) {
case CIRCLE:
circle(g2d, info);
break;
case RECT:
rectangle(g2d, info);
break;
case ELLIPSE:
ellipse(g2d, info);
break;
case LINE:
line(g2d, info);
break;
case POLYGON:
polygon(g2d, info);
break;
case POLYLINE:
polyline(g2d, info);
break;
case PATH:
path(g2d, info);
break;
default:
break;
}
}
}
public void transform(Graphics2D g2d, SVGInfo svgi, SVGInfo group) {
SVGTransformList transformList = null;
if (group.getTransformList() != null) {
transformList = group.getTransformList();
} else {
transformList = svgi.getTransformList();
}
if(transformList == null)
return;
int numPoints = transformList.getNumberOfItems();
for (int i = 0; i < numPoints; i++) {
SVGTransform point = transformList.getItem(i);
SVGMatrixImpl mtrx = (SVGMatrixImpl) point.getMatrix();
AffineTransform affine = new AffineTransform();
switch (point.getType()) {
case SVGTransform.SVG_TRANSFORM_MATRIX:
affine.concatenate(new AffineTransform(mtrx.getA(), mtrx.getB(), mtrx.getC(), mtrx.getD(), mtrx.getE(), mtrx.getF()));
break;
case SVGTransform.SVG_TRANSFORM_TRANSLATE:
affine.translate(mtrx.getE(), mtrx.getF());
break;
case SVGTransform.SVG_TRANSFORM_SCALE:
affine.scale(mtrx.getA(), mtrx.getD());
break;
case SVGTransform.SVG_TRANSFORM_ROTATE:
affine.rotate(Math.toRadians(mtrx.getA()), mtrx.getB(), mtrx.getC());
break;
case SVGTransform.SVG_TRANSFORM_SKEWX:
affine.concatenate(new AffineTransform(mtrx.getA(), mtrx.getB(), mtrx.getC(), mtrx.getD(), mtrx.getE(), mtrx.getF()));
break;
case SVGTransform.SVG_TRANSFORM_SKEWY:
affine.concatenate(new AffineTransform(mtrx.getA(), mtrx.getB(), mtrx.getC(), mtrx.getD(), mtrx.getE(), mtrx.getF()));
break;
}
g2d.transform(affine);
}
}
public void text(Graphics2D g2d, SVGInfo svgi) {
GeneralPath path = new GeneralPath();
path.setWindingRule(Path2D.WIND_NON_ZERO);
FontRenderContext frc = new FontRenderContext(null, false, false);
SVGLengthList dxList = svgi.getDxList();
SVGLengthList dyList = svgi.getDyList();
char[] cr = svgi.getText().toCharArray();
float x = svgi.getX();
float y = svgi.getY();
for (int i = 0; i < cr.length; i++) {
if (dxList != null && dxList.getNumberOfItems() > 0) {
try {
if(i == 0){
x = i + (dxList.getItem(i).getValue());
} else {
x = dxList.getItem(i).getValue() + x;
}
} catch (Exception e) {
x = 8 + x;
}
} else if (dyList != null && dyList.getNumberOfItems() > 0) {
try {
if(i == 0){
y = i + (dyList.getItem(i).getValue());
} else {
y = dyList.getItem(i).getValue() + y;
}
} catch (Exception e) {
y = 20 + y;
}
} else {
if (i > 0)
x = i * 8;
}
TextLayout tl = new TextLayout(String.valueOf(cr[i]), svgi.getFont(), frc);
Point2D.Float pos = new Point2D.Float(x, y);
AffineTransform textAt = AffineTransform.getTranslateInstance(pos.x, pos.y);
textAt.translate(x, y);
Shape textShape = tl.getOutline(textAt);
path.append(textShape, false);
}
path.closePath();
transform(g2d, svgi, new SVGInfo());
drawFillAndStroke(g2d, path, svgi);
}
private Shape createArc(float x1, float y1, float x2, float y2, float rx, float ry, float angle, boolean fA, boolean fS) {
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
double x1prime = (cosAngle * (x1 - x2) / 2) + (sinAngle * (y1 - y2) / 2);
double y1prime = (-sinAngle * (x1 - x2) / 2) + (cosAngle * (y1 - y2) / 2);
double rx2 = rx * rx;
double ry2 = ry * ry;
double x1prime2 = x1prime * x1prime;
double y1prime2 = y1prime * y1prime;
double radiiCheck = x1prime2 / rx2 + y1prime2 / ry2;
if (radiiCheck > 1) {
rx = (float) Math.sqrt(radiiCheck) * rx;
ry = (float) Math.sqrt(radiiCheck) * ry;
rx2 = rx * rx;
ry2 = ry * ry;
}
double squaredThing = (rx2 * ry2 - rx2 * y1prime2 - ry2 * x1prime2) / (rx2 * y1prime2 + ry2 * x1prime2);
if (squaredThing < 0) { // this may happen due to lack of precision
squaredThing = 0;
}
squaredThing = Math.sqrt(squaredThing);
if (fA == fS) {
squaredThing = -squaredThing;
}
double cXprime = squaredThing * rx * y1prime / ry;
double cYprime = squaredThing * -(ry * x1prime / rx);
double cx = cosAngle * cXprime - sinAngle * cYprime + (x1 + x2) / 2;
double cy = sinAngle * cXprime + cosAngle * cYprime + (y1 + y2) / 2;
double ux = 1;
double uy = 0;
double vx = (x1prime - cXprime) / rx;
double vy = (y1prime - cYprime) / ry;
double startAngle = Math.acos((ux * vx + uy * vy) / (Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy)));
if ((ux * vy - uy * vx) < 0) {
startAngle = -startAngle;
}
ux = (x1prime - cXprime) / rx;
uy = (y1prime - cYprime) / ry;
vx = (-x1prime - cXprime) / rx;
vy = (-y1prime - cYprime) / ry;
double angleExtent = Math.acos((ux * vx + uy * vy) / (Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy)));
if ((ux * vy - uy * vx) < 0) {
angleExtent = -angleExtent;
}
double angleExtentDegrees = Math.toDegrees(angleExtent);
double numCircles = Math.abs(angleExtentDegrees / 360.0);
if (numCircles > 1) {
if (angleExtentDegrees > 0) {
angleExtentDegrees -= 360 * Math.floor(numCircles);
} else {
angleExtentDegrees += 360 * Math.floor(numCircles);
}
angleExtent = Math.toRadians(angleExtentDegrees);
}
if (fS && angleExtent < 0) {
angleExtent += Math.toRadians(360.0);
} else if (!fS && angleExtent > 0) {
angleExtent -= Math.toRadians(360.0);
}
Shape arc = new Arc2D.Double(cx - rx, cy - ry, rx * 2, ry * 2, -Math.toDegrees(startAngle), -Math.toDegrees(angleExtent), Arc2D.OPEN);
arc = AffineTransform.getRotateInstance(angle, cx, cy).createTransformedShape(arc);
return arc;
}
private void drawFillAndStroke(Graphics2D g2d, Shape shape2d, SVGInfo svgi) {
BasicStroke basicStroke = null;
Color strokeColor = null;
Color fillColor = Color.BLACK;
float fillOpacity = 1.0F;
float strokeOpacity = 1.0F;
SVGInfo group = getSvgiGroup();
if (group.getStyle() != null && group.getStyle().getFillOpacity() != null) {
fillOpacity = Float.parseFloat(group.getStyle().getFillOpacity());
} else if (svgi.getStyle().getFillOpacity() != null) {
fillOpacity = Float.parseFloat(svgi.getStyle().getFillOpacity());
}
if (group.getStyle() != null && group.getStyle().getStrokeOpacity() != null) {
strokeOpacity = Float.parseFloat(group.getStyle().getStrokeOpacity());
} else if (svgi.getStyle().getStrokeOpacity() != null) {
strokeOpacity = Float.parseFloat(svgi.getStyle().getStrokeOpacity());
}
if (group.getStyle() != null && group.getStyle().getOpacity() != null) {
fillOpacity = Float.parseFloat(group.getStyle().getOpacity());
strokeOpacity = Float.parseFloat(group.getStyle().getOpacity());
} else if (svgi.getStyle().getOpacity() != null) {
fillOpacity = Float.parseFloat(svgi.getStyle().getOpacity());
strokeOpacity = Float.parseFloat(svgi.getStyle().getOpacity());
}
if (group.getStyle() != null && group.getStyle().getStroke() != null && !"none".equalsIgnoreCase(group.getStyle().getStroke())) {
Color color = ColorFactory.getInstance().getColor(group.getStyle().getStroke());
strokeColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), Math.round(255 * strokeOpacity));
basicStroke = getStroking(g2d, group);
} else if (svgi.getStyle().getStroke() != null && !"none".equalsIgnoreCase(svgi.getStyle().getStroke())) {
Color color = ColorFactory.getInstance().getColor(svgi.getStyle().getStroke());
strokeColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), Math.round(255 * strokeOpacity));
basicStroke = getStroking(g2d, svgi);
}
if (group.getStyle() != null && group.getStyle().getFill() != null && !"none".equalsIgnoreCase(group.getStyle().getFill())) {
Color color = ColorFactory.getInstance().getColor(group.getStyle().getFill());
fillColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), Math.round(255 * fillOpacity));
} else if (svgi.getStyle().getFill() != null && !"none".equalsIgnoreCase(svgi.getStyle().getFill())) {
Color color = ColorFactory.getInstance().getColor(svgi.getStyle().getFill());
fillColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), Math.round(255 * fillOpacity));
}
if (fillColor != null) {
g2d.setPaint(fillColor);
g2d.fill(shape2d);
}
if (strokeColor != null) {
g2d.setPaint(strokeColor);
g2d.draw(basicStroke.createStrokedShape(shape2d));
}
}
private BasicStroke getStroking(Graphics2D g2d, SVGInfo svgi) {
BasicStroke basicStroke;
int strokeWidth = 1;
int intLineCap = BasicStroke.CAP_BUTT;
int intlineJoin = BasicStroke.JOIN_BEVEL;
int miterlimit = 4;
if ("round".equals(svgi.getStyle().getStrokeLineCap())) {
intLineCap = BasicStroke.CAP_ROUND;
} else if ("square".equals(svgi.getStyle().getStrokeLineCap())) {
intLineCap = BasicStroke.CAP_SQUARE;
}
if ("round".equals(svgi.getStyle().getStrokeLineCap())) {
intlineJoin = BasicStroke.JOIN_ROUND;
} else if ("miter".equals(svgi.getStyle().getStrokeLineCap())) {
intlineJoin = BasicStroke.JOIN_MITER;
}
if (svgi.getStyle().getStrokeWidth() != null) {
strokeWidth = HtmlValues.getPixelSize(svgi.getStyle().getStrokeWidth(), null, 1);
}
if (svgi.getStyle().getStrokeMiterLimit() != null) {
miterlimit = HtmlValues.getPixelSize(svgi.getStyle().getStrokeMiterLimit(), null, 4);
}
if (svgi.getStyle().getStrokeDashArray() == null) {
basicStroke = new BasicStroke(strokeWidth, intLineCap, intlineJoin, miterlimit);
} else {
String parts[] = svgi.getStyle().getStrokeDashArray().split("\\s*,\\s*|\\s+");
float[] dashArray = new float[parts.length];
int i = 0;
for (String str : parts) {
dashArray[i] = Float.parseFloat(str);
i++;
}
basicStroke = new BasicStroke(strokeWidth, intLineCap, intlineJoin, miterlimit, dashArray, 0.0F);
}
if (basicStroke != null) {
g2d.setStroke(basicStroke);
}
return basicStroke;
}
private Point2D.Float convertCoordinate(Point2D.Float p1) {
Point2D.Float p = p1;
return p;
}
private ArrayList<SVGInfo> useChildren(Node element) {
ArrayList<SVGInfo> useList = new ArrayList<SVGInfo>();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node n = (Node) childNodes.item(i);
if (n instanceof SVGCircleElementImpl) {
SVGCircleElementImpl svgcircle = (SVGCircleElementImpl) n;
AbstractCSS2Properties style = svgcircle.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(CIRCLE);
svgi.setX(svgcircle.getCx().getBaseVal().getValue());
svgi.setY(svgcircle.getCy().getBaseVal().getValue());
svgi.setR(svgcircle.getR().getBaseVal().getValue());
if (svgcircle.getFill() != null) {
style.setFill(svgcircle.getFill());
}
if (svgcircle.getStroke() != null) {
style.setStroke(svgcircle.getStroke());
}
if (svgcircle.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgcircle.getStrokeDashArray());
}
if (svgcircle.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgcircle.getStrokeLineCap());
}
if (svgcircle.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgcircle.getStrokeMiterLimit());
}
if (svgcircle.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgcircle.getStrokeOpacity());
}
if (svgcircle.getStrokeWidth() != null) {
style.setStrokeWidth(svgcircle.getStrokeWidth());
}
svgi.setTransformList(svgcircle.getTransform().getBaseVal());
svgi.setStyle(style);
useList.add(svgi);
}
if (n instanceof SVGRectElementImpl) {
SVGRectElementImpl svgrect = (SVGRectElementImpl) n;
AbstractCSS2Properties style = svgrect.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(RECT);
svgi.setX(svgrect.getX().getBaseVal().getValue());
svgi.setY(svgrect.getY().getBaseVal().getValue());
svgi.setWidth(svgrect.getWidth().getBaseVal().getValue());
svgi.setHeight(svgrect.getHeight().getBaseVal().getValue());
svgi.setRx(svgrect.getRx().getBaseVal().getValue());
svgi.setRy(svgrect.getRy().getBaseVal().getValue());
if (svgrect.getFill() != null) {
style.setFill(svgrect.getFill());
}
if (svgrect.getStroke() != null) {
style.setStroke(svgrect.getStroke());
}
if (svgrect.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgrect.getStrokeDashArray());
}
if (svgrect.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgrect.getStrokeLineCap());
}
if (svgrect.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgrect.getStrokeMiterLimit());
}
if (svgrect.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgrect.getStrokeOpacity());
}
if (svgrect.getStrokeWidth() != null) {
style.setStrokeWidth(svgrect.getStrokeWidth());
}
svgi.setTransformList(svgrect.getTransform().getBaseVal());
svgi.setStyle(style);
useList.add(svgi);
}
if (n instanceof SVGEllipseElementImpl) {
SVGEllipseElementImpl svgellipse = (SVGEllipseElementImpl) n;
AbstractCSS2Properties style = svgellipse.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(ELLIPSE);
svgi.setX(svgellipse.getCx().getBaseVal().getValue());
svgi.setY(svgellipse.getCy().getBaseVal().getValue());
svgi.setRx(svgellipse.getRx().getBaseVal().getValue());
svgi.setRy(svgellipse.getRy().getBaseVal().getValue());
if (svgellipse.getFill() != null) {
style.setFill(svgellipse.getFill());
}
if (svgellipse.getStroke() != null) {
style.setStroke(svgellipse.getStroke());
}
if (svgellipse.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgellipse.getStrokeDashArray());
}
if (svgellipse.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgellipse.getStrokeLineCap());
}
if (svgellipse.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgellipse.getStrokeMiterLimit());
}
if (svgellipse.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgellipse.getStrokeOpacity());
}
if (svgellipse.getStrokeWidth() != null) {
style.setStrokeWidth(svgellipse.getStrokeWidth());
}
svgi.setTransformList(svgellipse.getTransform().getBaseVal());
svgi.setStyle(svgellipse.getStyle());
useList.add(svgi);
}
if (n instanceof SVGLineElementImpl) {
SVGLineElementImpl svgline = (SVGLineElementImpl) n;
AbstractCSS2Properties style = svgline.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(LINE);
svgi.setX1(svgline.getX1().getBaseVal().getValue());
svgi.setY1(svgline.getY1().getBaseVal().getValue());
svgi.setX2(svgline.getX2().getBaseVal().getValue());
svgi.setY2(svgline.getY2().getBaseVal().getValue());
if (svgline.getFill() != null) {
style.setFill(svgline.getFill());
}
if (svgline.getStroke() != null) {
style.setStroke(svgline.getStroke());
}
if (svgline.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgline.getStrokeDashArray());
}
if (svgline.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgline.getStrokeLineCap());
}
if (svgline.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgline.getStrokeMiterLimit());
}
if (svgline.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgline.getStrokeOpacity());
}
if (svgline.getStrokeWidth() != null) {
style.setStrokeWidth(svgline.getStrokeWidth());
}
svgi.setTransformList(svgline.getTransform().getBaseVal());
svgi.setStyle(svgline.getStyle());
useList.add(svgi);
}
if (n instanceof SVGPolylineElementImpl) {
SVGPolylineElementImpl svgline = (SVGPolylineElementImpl) n;
AbstractCSS2Properties style = svgline.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(POLYLINE);
svgi.setPoilist(svgline.getPoints());
if (svgline.getFill() != null) {
style.setFill(svgline.getFill());
}
if (svgline.getStroke() != null) {
style.setStroke(svgline.getStroke());
}
if (svgline.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgline.getStrokeDashArray());
}
if (svgline.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgline.getStrokeLineCap());
}
if (svgline.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgline.getStrokeMiterLimit());
}
if (svgline.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgline.getStrokeOpacity());
}
if (svgline.getStrokeWidth() != null) {
style.setStrokeWidth(svgline.getStrokeWidth());
}
svgi.setTransformList(svgline.getTransform().getBaseVal());
svgi.setStyle(svgline.getStyle());
useList.add(svgi);
}
if (n instanceof SVGPolygonElementImpl) {
SVGPolygonElementImpl svgline = (SVGPolygonElementImpl) n;
AbstractCSS2Properties style = svgline.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(POLYGON);
svgi.setPoilist(svgline.getPoints());
if (svgline.getFill() != null) {
style.setFill(svgline.getFill());
}
if (svgline.getStroke() != null) {
style.setStroke(svgline.getStroke());
}
if (svgline.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgline.getStrokeDashArray());
}
if (svgline.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgline.getStrokeLineCap());
}
if (svgline.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgline.getStrokeMiterLimit());
}
if (svgline.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgline.getStrokeOpacity());
}
if (svgline.getStrokeWidth() != null) {
style.setStrokeWidth(svgline.getStrokeWidth());
}
svgi.setTransformList(svgline.getTransform().getBaseVal());
svgi.setStyle(svgline.getStyle());
useList.add(svgi);
}
if (n instanceof SVGPathElementImpl) {
SVGPathElementImpl svgpath = (SVGPathElementImpl) n;
AbstractCSS2Properties style = svgpath.getStyle();
SVGInfo svgi = new SVGInfo();
svgi.setMethod(PATH);
if (svgpath.getFill() != null) {
style.setFill(svgpath.getFill());
}
if (svgpath.getStroke() != null) {
style.setStroke(svgpath.getStroke());
}
if (svgpath.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgpath.getStrokeDashArray());
}
if (svgpath.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgpath.getStrokeLineCap());
}
if (svgpath.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgpath.getStrokeMiterLimit());
}
if (svgpath.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgpath.getStrokeOpacity());
}
if (svgpath.getStrokeWidth() != null) {
style.setStrokeWidth(svgpath.getStrokeWidth());
}
svgi.setPathSegList(svgpath.getPathSegList());
svgi.setStyle(svgpath.getStyle());
useList.add(svgi);
}
if (n instanceof SVGGElementImpl) {
SVGGElementImpl svgGroup = (SVGGElementImpl) n;
AbstractCSS2Properties style = svgGroup.getStyle();
if (svgGroup.getFill() != null) {
style.setFill(svgGroup.getFill());
}
if (svgGroup.getStroke() != null) {
style.setStroke(svgGroup.getStroke());
}
if (svgGroup.getStrokeDashArray() != null) {
style.setStrokeDashArray(svgGroup.getStrokeDashArray());
}
if (svgGroup.getStrokeLineCap() != null) {
style.setStrokeLineCap(svgGroup.getStrokeLineCap());
}
if (svgGroup.getStrokeMiterLimit() != null) {
style.setStrokeMiterLimit(svgGroup.getStrokeMiterLimit());
}
if (svgGroup.getStrokeOpacity() != null) {
style.setStrokeOpacity(svgGroup.getStrokeOpacity());
}
if (svgGroup.getStrokeWidth() != null) {
style.setStrokeWidth(svgGroup.getStrokeWidth());
}
SVGInfo svgiGroup = new SVGInfo();
svgiGroup.setTransformList(svgGroup.getTransform().getBaseVal());
svgiGroup.setStyle(svgGroup.getStyle());
setSvgiGroup(svgiGroup);
NodeList gChildNodes = svgGroup.getChildNodes();
for (int g = 0; g < gChildNodes.getLength(); g++) {
Node n1 = (Node) gChildNodes.item(g);
useChildren(n1);
}
}
if (n instanceof SVGUseElementImpl) {
SVGUseElementImpl use = (SVGUseElementImpl) n;
SVGInfo svgi = new SVGInfo();
svgi.setMethod(USE);
svgi.setHref(use.getHref().getBaseVal());
svgi.setX(use.getX().getBaseVal().getValue());
svgi.setY(use.getY().getBaseVal().getValue());
svgi.setTransformList(use.getTransform().getBaseVal());
useList.add(svgi);
}
}
return useList;
}
/**
* @return the svgiGroup
*/
public SVGInfo getSvgiGroup() {
return svgiGroup;
}
/**
* @param svgiGroup the svgiGroup to set
*/
public void setSvgiGroup(SVGInfo svgiGroup) {
this.svgiGroup = svgiGroup;
}
}