package org.xmind.ui.internal.svgsupport; import java.util.HashMap; import java.util.Map; import org.eclipse.draw2d.Graphics; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.util.Util; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.LineAttributes; import org.eclipse.swt.graphics.PathData; import org.eclipse.swt.graphics.Pattern; import org.eclipse.swt.internal.DPIUtil; import org.eclipse.swt.widgets.Display; import org.w3c.dom.Element; import org.xmind.gef.draw2d.geometry.PrecisionRectangle; import org.xmind.gef.draw2d.graphics.Path; @SuppressWarnings("restriction") abstract class SVGShape implements SVGDefinition, Cloneable { public static final PrecisionRectangle INVALID_RECT = new PrecisionRectangle( 0f, 0f, -1f, -1f); private static final int RATIO = 255; // ratio from svg to swt static Map<String, SVGDefinition> idRefs = new HashMap<String, SVGDefinition>(); private SVGShapeInfoMap info; private PrecisionRectangle rect; private PathData pathData; private ResourceManager resourceManager; SVGShape() { this.info = new SVGShapeInfoMap(); } abstract Path generatePath(Display device); abstract PrecisionRectangle generateRectangle(); void parse(Element implementation, SVGShape parent) { info.parse(implementation, parent == null ? null : parent.info); } static SVGShape parseShape(Element ele, SVGShape parent) { String type = ele.getTagName(); if (type == null) return null; SVGShape shape = SVGShapeFactory.createSVGShape(type); if (shape != null) shape.parse(ele, parent); return shape; } float getFloatAttribute(Element ele, String name) { if (ele.hasAttribute(name)) return Float.valueOf(ele.getAttribute(name)); return 0f; } void paintImage(Graphics graphics, Display device) { Path path = null; if (pathData == null) { path = generatePath(device); pathData = path.getPathData(); } else path = new Path(device, pathData); if (this.rect == null || this.rect == INVALID_RECT) this.rect = generateRectangle(); paint(graphics, rect, path); path.dispose(); } private void paint(Graphics graphics, PrecisionRectangle rect, Path path) { // pre paint boolean statePushed = prePaint(graphics); Color background = null; Color foreground = null; Pattern pattern = null; PrecisionRectangle correctRect = null; // check bounds if (rect == INVALID_RECT) { float[] rectNums = new float[4]; path.getBounds(rectNums); if (Util.isWindows()) { float[] autoScaleDown = DPIUtil.autoScaleDown(rectNums); rectNums[0] = autoScaleDown[0]; rectNums[1] = autoScaleDown[1]; rectNums[2] = autoScaleDown[2]; rectNums[3] = autoScaleDown[3]; } correctRect = new PrecisionRectangle(rectNums[0], rectNums[1], rectNums[2], rectNums[3]); } else { correctRect = rect; } // paint fill SVGColor co = info.getFillColor(); if (co != null) { float alpha = RATIO * info.getFillOpacity(); graphics.setFillRule(info.getFillRule() .equals(SVGShapeInfoMap.FILL_RULE_NONZERO_STRING) ? SWT.FILL_WINDING : SWT.FILL_EVEN_ODD); if (co.getLinearGradient() != null) { pattern = getLinearGradientPattern(co, alpha, correctRect); graphics.setBackgroundPattern(pattern); } else { background = resourceManager.createColor(co.getRGB()); graphics.setBackgroundColor(background); } graphics.fillPath(path); } // paint stroke co = info.getStrokeColor(); if (co != null) { float alpha = RATIO * info.getStrokeOpacity(); if (co.getLinearGradient() != null) { PrecisionRectangle rectExpand = new PrecisionRectangle( correctRect); rectExpand.expand(info.getLineWidth(), info.getLineWidth()); pattern = getLinearGradientPattern(co, alpha, rectExpand); graphics.setForegroundPattern(pattern); } else { foreground = resourceManager.createColor(co.getRGB()); graphics.setAlpha((int) alpha); graphics.setForegroundColor(foreground); } setApplyLineStyle(graphics); graphics.drawPath(path); } // post paint postPaint(graphics, statePushed); } private Pattern getLinearGradientPattern(SVGColor co, float alpha, PrecisionRectangle rect) { LinearGradient linearGradient = (LinearGradient) co.getLinearGradient(); SVGColor back = linearGradient.getBackGroundColor(); SVGColor fore = linearGradient.getForeGroundColor(); Color foreground = resourceManager.createColor(fore.getRGB()); Color background = resourceManager.createColor(back.getRGB()); Pattern pattern = (Pattern) resourceManager .create(new PatternResourceDescriptor( (float) (rect.x + linearGradient.getX1() * rect.width), (float) (rect.y + linearGradient.getY1() * rect.height), (float) (rect.x + linearGradient.getX2() * rect.width), (float) (rect.y + linearGradient.getY2() * rect.height), (int) (alpha * linearGradient.getForeOpacity()), foreground, (int) (alpha * linearGradient.getBackOpacity()), background)); return pattern; } boolean prePaint(Graphics graphics) { boolean statePushed = false; try { graphics.pushState(); statePushed = true; } catch (Exception e) { statePushed = false; } if (haveTransformProperty()) { //FIXME apply transform matrix : transform="matrix(m1 m2 m3 m4 m5 m6)" for (TransformElement element : this.info.getTransform() .getList()) { element.transform(graphics); } } return statePushed; } private boolean haveTransformProperty() { if (info != null && info.getTransform() != null) { SVGTransform transform = info.getTransform(); if (transform.getList() != null) return true; } return false; } private void setApplyLineStyle(Graphics graphics) { LineAttributes lineAttribute = new LineAttributes( this.info.getLineWidth()); lineAttribute.style = this.info.getLineStyle(); lineAttribute.dash = info.getLineDash(); lineAttribute.dashOffset = this.info.getLineDashOffset(); lineAttribute.join = this.info.getLineJoin(); lineAttribute.miterLimit = this.info.getLineMiterLimit(); graphics.setLineAttributes(lineAttribute); } void postPaint(Graphics graphics, boolean statePushed) { if (statePushed) { try { graphics.restoreState(); graphics.popState(); } catch (Throwable t) { } } } @Override protected SVGShape clone() { return this.clone(); } void setResourceManager(ResourceManager resourceManager) { this.resourceManager = resourceManager; } ResourceManager getResourceManager() { return resourceManager; } public SVGShapeInfoMap getInfo() { return info; } public void setInfo(SVGShapeInfoMap info) { this.info = info; } }