PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/pptx/src/org/apache/poi/xslf/usermodel/RenderableShape.java

https://github.com/minstrelsy/POI-Android
Java | 633 lines | 462 code | 79 blank | 92 comment | 105 complexity | 6e68dd3c8ec32b1c5501783941fcea98 MD5 | raw file
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.xslf.usermodel;
  20. import java.lang.reflect.Constructor;
  21. import java.util.ArrayList;
  22. import java.util.Arrays;
  23. import java.util.Collection;
  24. import java.util.Comparator;
  25. import net.pbdavey.awt.Graphics2D;
  26. import org.apache.poi.openxml4j.opc.PackagePart;
  27. import org.apache.poi.openxml4j.opc.PackageRelationship;
  28. import org.apache.poi.util.Internal;
  29. import org.apache.poi.util.Units;
  30. import org.apache.poi.xslf.model.PropertyFetcher;
  31. import org.apache.poi.xslf.model.geom.Context;
  32. import org.apache.poi.xslf.model.geom.CustomGeometry;
  33. import org.apache.poi.xslf.model.geom.Guide;
  34. import org.apache.poi.xslf.model.geom.IAdjustableShape;
  35. import org.apache.poi.xslf.model.geom.Outline;
  36. import org.apache.poi.xslf.model.geom.Path;
  37. import org.apache.xmlbeans.XmlObject;
  38. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
  39. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
  40. import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
  41. import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
  42. import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop;
  43. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
  44. import org.openxmlformats.schemas.drawingml.x2006.main.CTNoFillProperties;
  45. import org.openxmlformats.schemas.drawingml.x2006.main.CTPathShadeProperties;
  46. import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
  47. //import org.openxmlformats.schemas.drawingml.x2006.main.CTPathShadeProperties;
  48. import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
  49. import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
  50. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
  51. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
  52. import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
  53. import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
  54. //import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
  55. import and.awt.BasicStroke;
  56. import and.awt.BufferedImage;
  57. import and.awt.Color;
  58. import and.awt.Paint;
  59. import and.awt.Shape;
  60. import and.awt.Stroke;
  61. import and.awt.TexturePaint;
  62. import and.awt.geom.AffineTransform;
  63. import and.awt.geom.Point2D;
  64. import and.awt.geom.Rectangle2D;
  65. /**
  66. * Encapsulates logic to translate DrawingML objects to Java2D
  67. */
  68. @Internal
  69. class RenderableShape {
  70. public final static Color NO_PAINT = new Color(0xFF, 0xFF, 0xFF, 0);
  71. private XSLFSimpleShape _shape;
  72. public RenderableShape(XSLFSimpleShape shape){
  73. _shape = shape;
  74. }
  75. /**
  76. * Convert shape fill into and.awt.Paint. The result is either Color or
  77. * TexturePaint or GradientPaint or null
  78. *
  79. * @param graphics the target graphics
  80. * @param obj the xml to read. Must contain elements from the EG_ColorChoice group:
  81. * <code>
  82. * a:scrgbClr RGB Color Model - Percentage Variant
  83. * a:srgbClr RGB Color Model - Hex Variant
  84. * a:hslClr Hue, Saturation, Luminance Color Model
  85. * a:sysClr System Color
  86. * a:schemeClr Scheme Color
  87. * a:prstClr Preset Color
  88. * </code>
  89. *
  90. * @param phClr context color
  91. * @param parentPart the parent package part. Any external references (images, etc.) are resolved relative to it.
  92. *
  93. * @return the applied Paint or null if none was applied
  94. */
  95. public Paint selectPaint(Graphics2D graphics, XmlObject obj, CTSchemeColor phClr, PackagePart parentPart) {
  96. XSLFTheme theme = _shape.getSheet().getTheme();
  97. Paint paint = null;
  98. if (obj instanceof CTNoFillProperties) {
  99. paint = NO_PAINT;
  100. }
  101. else if (obj instanceof CTSolidColorFillProperties) {
  102. CTSolidColorFillProperties solidFill = (CTSolidColorFillProperties) obj;
  103. XSLFColor c = new XSLFColor(solidFill, theme, phClr);
  104. paint = c.getColor();
  105. }
  106. else if (obj instanceof CTBlipFillProperties) {
  107. CTBlipFillProperties blipFill = (CTBlipFillProperties)obj;
  108. paint = createTexturePaint(blipFill, graphics, parentPart);
  109. }
  110. else if (obj instanceof CTGradientFillProperties) {
  111. Rectangle2D anchor = getAnchor(graphics);
  112. CTGradientFillProperties gradFill = (CTGradientFillProperties) obj;
  113. if (gradFill.isSetLin()) {
  114. paint = createLinearGradientPaint(graphics, gradFill, anchor, theme, phClr);
  115. } else if (gradFill.isSetPath()){
  116. CTPathShadeProperties ps = gradFill.getPath();
  117. if(ps.getPath() == STPathShadeType.CIRCLE){
  118. paint = createRadialGradientPaint(gradFill, anchor, theme, phClr);
  119. } else if (ps.getPath() == STPathShadeType.SHAPE){
  120. paint = toRadialGradientPaint(gradFill, anchor, theme, phClr);
  121. }
  122. }
  123. }
  124. return paint;
  125. }
  126. private Paint createTexturePaint(CTBlipFillProperties blipFill, Graphics2D graphics,
  127. PackagePart parentPart){
  128. Paint paint = null;
  129. CTBlip blip = blipFill.getBlip();
  130. String blipId = blip.getEmbed();
  131. PackageRelationship rel = parentPart.getRelationship(blipId);
  132. if (rel != null) {
  133. XSLFImageRenderer renderer = null;
  134. // if (graphics != null)
  135. // renderer = (XSLFImageRenderer) graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER);
  136. if (renderer == null) renderer = new XSLFImageRenderer();
  137. try {
  138. BufferedImage img = renderer.readImage(parentPart.getRelatedPart(rel));
  139. // XXX: DD
  140. // if (blip.sizeOfAlphaModFixArray() > 0) {
  141. // float alpha = blip.getAlphaModFixArray(0).getAmt() / 100000.f;
  142. // AlphaComposite ac = AlphaComposite.getInstance(
  143. // AlphaComposite.SRC_OVER, alpha);
  144. // if (graphics != null) graphics.setComposite(ac);
  145. // }
  146. if(img != null) {
  147. paint = new TexturePaint(
  148. img, new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
  149. }
  150. }
  151. catch (Exception e) {
  152. e.printStackTrace();
  153. }
  154. }
  155. return paint;
  156. }
  157. private Paint createLinearGradientPaint(
  158. Graphics2D graphics,
  159. CTGradientFillProperties gradFill, Rectangle2D anchor,
  160. XSLFTheme theme, CTSchemeColor phClr) {
  161. double angle = gradFill.getLin().getAng() / 60000;
  162. @SuppressWarnings("deprecation")
  163. CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
  164. Arrays.sort(gs, new Comparator<CTGradientStop>() {
  165. public int compare(CTGradientStop o1, CTGradientStop o2) {
  166. Integer pos1 = o1.getPos();
  167. Integer pos2 = o2.getPos();
  168. return pos1.compareTo(pos2);
  169. }
  170. });
  171. Color[] colors = new Color[gs.length];
  172. float[] fractions = new float[gs.length];
  173. AffineTransform at = AffineTransform.getRotateInstance(
  174. Math.toRadians(angle),
  175. anchor.getX() + anchor.getWidth() / 2,
  176. anchor.getY() + anchor.getHeight() / 2);
  177. double diagonal = Math.sqrt(anchor.getHeight() * anchor.getHeight() + anchor.getWidth() * anchor.getWidth());
  178. Point2D p1 = new Point2D.Double(anchor.getX() + anchor.getWidth() / 2 - diagonal / 2,
  179. anchor.getY() + anchor.getHeight() / 2);
  180. p1 = at.transform(p1, null);
  181. Point2D p2 = new Point2D.Double(anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight() / 2);
  182. p2 = at.transform(p2, null);
  183. snapToAnchor(p1, anchor);
  184. snapToAnchor(p2, anchor);
  185. for (int i = 0; i < gs.length; i++) {
  186. CTGradientStop stop = gs[i];
  187. colors[i] = new XSLFColor(stop, theme, phClr).getColor();
  188. fractions[i] = stop.getPos() / 100000.f;
  189. }
  190. AffineTransform grAt = new AffineTransform();
  191. if(gradFill.isSetRotWithShape() || !gradFill.getRotWithShape()) {
  192. double rotation = _shape.getRotation();
  193. if (rotation != 0.) {
  194. double centerX = anchor.getX() + anchor.getWidth() / 2;
  195. double centerY = anchor.getY() + anchor.getHeight() / 2;
  196. grAt.translate(centerX, centerY);
  197. grAt.rotate(Math.toRadians(-rotation));
  198. grAt.translate(-centerX, -centerY);
  199. }
  200. }
  201. // Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+
  202. Paint paint = null;
  203. try {
  204. Class clz = Class.forName("and.awt.LinearGradientPaint");
  205. Class clzCycleMethod = Class.forName("and.awt.MultipleGradientPaint$CycleMethod");
  206. Class clzColorSpaceType = Class.forName("and.awt.MultipleGradientPaint$ColorSpaceType");
  207. Constructor c =
  208. clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class,
  209. clzCycleMethod, clzColorSpaceType, AffineTransform.class);
  210. paint = (Paint) c.newInstance(p1, p2, fractions, colors,
  211. Enum.valueOf(clzCycleMethod, "NO_CYCLE"),
  212. Enum.valueOf(clzColorSpaceType, "SRGB"), grAt);
  213. } catch (ClassNotFoundException e) {
  214. // XXX: DD
  215. // paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]);
  216. } catch (Exception e) {
  217. throw new RuntimeException(e);
  218. }
  219. return paint;
  220. }
  221. /**
  222. * gradients with type=shape are enot supported by Java graphics.
  223. * We approximate it with a radial gradient.
  224. */
  225. private static Paint toRadialGradientPaint(
  226. CTGradientFillProperties gradFill, Rectangle2D anchor,
  227. XSLFTheme theme, CTSchemeColor phClr) {
  228. @SuppressWarnings("deprecation")
  229. CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
  230. Arrays.sort(gs, new Comparator<CTGradientStop>() {
  231. public int compare(CTGradientStop o1, CTGradientStop o2) {
  232. Integer pos1 = o1.getPos();
  233. Integer pos2 = o2.getPos();
  234. return pos1.compareTo(pos2);
  235. }
  236. });
  237. gs[1].setPos(50000);
  238. CTGradientFillProperties g = CTGradientFillProperties.Factory.newInstance();
  239. g.set(gradFill);
  240. g.getGsLst().setGsArray(new CTGradientStop[]{gs[0], gs[1]});
  241. return createRadialGradientPaint(g, anchor, theme, phClr);
  242. }
  243. private static Paint createRadialGradientPaint(
  244. CTGradientFillProperties gradFill, Rectangle2D anchor,
  245. XSLFTheme theme, CTSchemeColor phClr) {
  246. @SuppressWarnings("deprecation")
  247. CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
  248. Point2D pCenter = new Point2D.Double(anchor.getX() + anchor.getWidth()/2,
  249. anchor.getY() + anchor.getHeight()/2);
  250. float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
  251. Arrays.sort(gs, new Comparator<CTGradientStop>() {
  252. public int compare(CTGradientStop o1, CTGradientStop o2) {
  253. Integer pos1 = o1.getPos();
  254. Integer pos2 = o2.getPos();
  255. return pos1.compareTo(pos2);
  256. }
  257. });
  258. Color[] colors = new Color[gs.length];
  259. float[] fractions = new float[gs.length];
  260. for (int i = 0; i < gs.length; i++) {
  261. CTGradientStop stop = gs[i];
  262. colors[i] = new XSLFColor(stop, theme, phClr).getColor();
  263. fractions[i] = stop.getPos() / 100000.f;
  264. }
  265. // Trick to return GradientPaint on JDK 1.5 and RadialGradientPaint on JDK 1.6+
  266. Paint paint = null;
  267. try {
  268. Class clz = Class.forName("and.awt.RadialGradientPaint");
  269. Constructor c =
  270. clz.getConstructor(Point2D.class, float.class,
  271. float[].class, Color[].class);
  272. paint = (Paint) c.newInstance(pCenter, radius, fractions, colors);
  273. } catch (ClassNotFoundException e) {
  274. // the result on JDK 1.5 is incorrect, but it is better than nothing
  275. // paint = new GradientPaint(
  276. // new Point2D.Double(anchor.getX(), anchor.getY()),
  277. // colors[0], pCenter, colors[colors.length - 1]);
  278. } catch (Exception e) {
  279. throw new RuntimeException(e);
  280. }
  281. return paint;
  282. }
  283. private static void snapToAnchor(Point2D p, Rectangle2D anchor) {
  284. if (p.getX() < anchor.getX()) {
  285. p.setLocation(anchor.getX(), p.getY());
  286. } else if (p.getX() > (anchor.getX() + anchor.getWidth())) {
  287. p.setLocation(anchor.getX() + anchor.getWidth(), p.getY());
  288. }
  289. if (p.getY() < anchor.getY()) {
  290. p.setLocation(p.getX(), anchor.getY());
  291. } else if (p.getY() > (anchor.getY() + anchor.getHeight())) {
  292. p.setLocation(p.getX(), anchor.getY() + anchor.getHeight());
  293. }
  294. }
  295. Paint getPaint(Graphics2D graphics, XmlObject spPr, CTSchemeColor phClr) {
  296. Paint paint = null;
  297. for (XmlObject obj : spPr.selectPath("*")) {
  298. paint = selectPaint(graphics, obj, phClr, _shape.getSheet().getPackagePart());
  299. if(paint != null) break;
  300. }
  301. return paint == NO_PAINT ? null : paint;
  302. }
  303. /**
  304. * fetch shape fill as a and.awt.Paint
  305. *
  306. * @return either Color or GradientPaint or TexturePaint or null
  307. */
  308. Paint getFillPaint(final Graphics2D graphics) {
  309. PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>() {
  310. public boolean fetch(XSLFSimpleShape shape) {
  311. CTShapeProperties spPr = shape.getSpPr();
  312. if (spPr.isSetNoFill()) {
  313. setValue(RenderableShape.NO_PAINT); // use it as 'nofill' value
  314. return true;
  315. }
  316. Paint paint = getPaint(graphics, spPr, null);
  317. if (paint != null) {
  318. setValue(paint);
  319. return true;
  320. }
  321. return false;
  322. }
  323. };
  324. _shape.fetchShapeProperty(fetcher);
  325. Paint paint = fetcher.getValue();
  326. if (paint == null) {
  327. // fill color was not found, check if it is defined in the theme
  328. CTShapeStyle style = _shape.getSpStyle();
  329. if (style != null) {
  330. // get a reference to a fill style within the style matrix.
  331. CTStyleMatrixReference fillRef = style.getFillRef();
  332. // The idx attribute refers to the index of a fill style or
  333. // background fill style within the presentation's style matrix, defined by the fmtScheme element.
  334. // value of 0 or 1000 indicates no background,
  335. // values 1-999 refer to the index of a fill style within the fillStyleLst element
  336. // values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
  337. int idx = (int)fillRef.getIdx();
  338. CTSchemeColor phClr = fillRef.getSchemeClr();
  339. XSLFSheet sheet = _shape.getSheet();
  340. XSLFTheme theme = sheet.getTheme();
  341. XmlObject fillProps = null;
  342. if(idx >= 1 && idx <= 999){
  343. fillProps = theme.getXmlObject().
  344. getThemeElements().getFmtScheme().getFillStyleLst().selectPath("*")[idx - 1];
  345. } else if (idx >= 1001 ){
  346. fillProps = theme.getXmlObject().
  347. getThemeElements().getFmtScheme().getBgFillStyleLst().selectPath("*")[idx - 1001];
  348. }
  349. if(fillProps != null) {
  350. paint = selectPaint(graphics, fillProps, phClr, sheet.getPackagePart());
  351. }
  352. }
  353. }
  354. return paint == RenderableShape.NO_PAINT ? null : paint;
  355. }
  356. public Paint getLinePaint(final Graphics2D graphics) {
  357. PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>() {
  358. public boolean fetch(XSLFSimpleShape shape) {
  359. CTLineProperties spPr = shape.getSpPr().getLn();
  360. if (spPr != null) {
  361. if (spPr.isSetNoFill()) {
  362. setValue(NO_PAINT); // use it as 'nofill' value
  363. return true;
  364. }
  365. Paint paint = getPaint(graphics, spPr, null);
  366. if (paint != null) {
  367. setValue(paint);
  368. return true;
  369. }
  370. }
  371. return false;
  372. }
  373. };
  374. _shape.fetchShapeProperty(fetcher);
  375. Paint paint = fetcher.getValue();
  376. if (paint == null) {
  377. // line color was not found, check if it is defined in the theme
  378. CTShapeStyle style = _shape.getSpStyle();
  379. if (style != null) {
  380. // get a reference to a line style within the style matrix.
  381. CTStyleMatrixReference lnRef = style.getLnRef();
  382. int idx = (int)lnRef.getIdx();
  383. CTSchemeColor phClr = lnRef.getSchemeClr();
  384. if(idx > 0){
  385. XSLFTheme theme = _shape.getSheet().getTheme();
  386. XmlObject lnProps = theme.getXmlObject().
  387. getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1];
  388. paint = getPaint(graphics, lnProps, phClr);
  389. }
  390. }
  391. }
  392. return paint == NO_PAINT ? null : paint;
  393. }
  394. /**
  395. * convert PPT dash into and.awt.BasicStroke
  396. *
  397. * The mapping is derived empirically on PowerPoint 2010
  398. */
  399. private static float[] getDashPattern(LineDash lineDash, float lineWidth) {
  400. float[] dash = null;
  401. switch (lineDash) {
  402. case SYS_DOT:
  403. dash = new float[]{lineWidth, lineWidth};
  404. break;
  405. case SYS_DASH:
  406. dash = new float[]{2 * lineWidth, 2 * lineWidth};
  407. break;
  408. case DASH:
  409. dash = new float[]{3 * lineWidth, 4 * lineWidth};
  410. break;
  411. case DASH_DOT:
  412. dash = new float[]{4 * lineWidth, 3 * lineWidth, lineWidth,
  413. 3 * lineWidth};
  414. break;
  415. case LG_DASH:
  416. dash = new float[]{8 * lineWidth, 3 * lineWidth};
  417. break;
  418. case LG_DASH_DOT:
  419. dash = new float[]{8 * lineWidth, 3 * lineWidth, lineWidth,
  420. 3 * lineWidth};
  421. break;
  422. case LG_DASH_DOT_DOT:
  423. dash = new float[]{8 * lineWidth, 3 * lineWidth, lineWidth,
  424. 3 * lineWidth, lineWidth, 3 * lineWidth};
  425. break;
  426. }
  427. return dash;
  428. }
  429. public Stroke applyStroke(Graphics2D graphics) {
  430. float lineWidth = (float) _shape.getLineWidth();
  431. if(lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt
  432. LineDash lineDash = _shape.getLineDash();
  433. float[] dash = null;
  434. float dash_phase = 0;
  435. if (lineDash != null) {
  436. dash = getDashPattern(lineDash, lineWidth);
  437. }
  438. int cap = BasicStroke.CAP_BUTT;
  439. LineCap lineCap = _shape.getLineCap();
  440. if (lineCap != null) {
  441. switch (lineCap) {
  442. case ROUND:
  443. cap = BasicStroke.CAP_ROUND;
  444. break;
  445. case SQUARE:
  446. cap = BasicStroke.CAP_SQUARE;
  447. break;
  448. default:
  449. cap = BasicStroke.CAP_BUTT;
  450. break;
  451. }
  452. }
  453. int meter = BasicStroke.JOIN_ROUND;
  454. Stroke stroke = new BasicStroke(lineWidth, cap, meter, Math.max(1, lineWidth), dash,
  455. dash_phase);
  456. graphics.setStroke(stroke);
  457. return stroke;
  458. }
  459. public void render(Graphics2D graphics){
  460. Collection<Outline> elems = computeOutlines(graphics);
  461. // shadow
  462. XSLFShadow shadow = _shape.getShadow();
  463. // first fill
  464. Paint fill = getFillPaint(graphics);
  465. Paint line = getLinePaint(graphics);
  466. applyStroke(graphics); // the stroke applies both to the shadow and the shape
  467. // first paint the shadow
  468. if(shadow != null) for(Outline o : elems){
  469. if(o.getPath().isFilled()){
  470. if(fill != null) shadow.fill(graphics, o.getOutline());
  471. else if(line != null) shadow.draw(graphics, o.getOutline());
  472. }
  473. }
  474. // then fill the shape interior
  475. if(fill != null) for(Outline o : elems){
  476. if(o.getPath().isFilled()){
  477. graphics.setPaint(fill);
  478. graphics.fill(o.getOutline());
  479. }
  480. }
  481. // then draw any content within this shape (text, image, etc.)
  482. _shape.drawContent(graphics);
  483. // then stroke the shape outline
  484. if(line != null) for(Outline o : elems){
  485. if(o.getPath().isStroked()){
  486. graphics.setPaint(line);
  487. graphics.draw(o.getOutline());
  488. }
  489. }
  490. }
  491. private Collection<Outline> computeOutlines(Graphics2D graphics) {
  492. Collection<Outline> lst = new ArrayList<Outline>();
  493. CustomGeometry geom = _shape.getGeometry();
  494. if(geom == null) {
  495. return lst;
  496. }
  497. Rectangle2D anchor = getAnchor(graphics);
  498. for (Path p : geom) {
  499. double w = p.getW() == -1 ? anchor.getWidth() * Units.EMU_PER_POINT : p.getW();
  500. double h = p.getH() == -1 ? anchor.getHeight() * Units.EMU_PER_POINT : p.getH();
  501. // the guides in the shape definitions are all defined relative to each other,
  502. // so we build the path starting from (0,0).
  503. final Rectangle2D pathAnchor = new Rectangle2D.Double(
  504. 0,
  505. 0,
  506. w,
  507. h
  508. );
  509. Context ctx = new Context(geom, pathAnchor, new IAdjustableShape() {
  510. public Guide getAdjustValue(String name) {
  511. CTPresetGeometry2D prst = _shape.getSpPr().getPrstGeom();
  512. if (prst.isSetAvLst()) {
  513. for (CTGeomGuide g : prst.getAvLst().getGdList()) {
  514. if (g.getName().equals(name)) {
  515. return new Guide(g);
  516. }
  517. }
  518. }
  519. return null;
  520. }
  521. }) ;
  522. Shape gp = p.getPath(ctx);
  523. // translate the result to the canvas coordinates in points
  524. AffineTransform at = new AffineTransform();
  525. at.translate(anchor.getX(), anchor.getY());
  526. double scaleX, scaleY;
  527. if (p.getW() != -1) {
  528. scaleX = anchor.getWidth() / p.getW();
  529. } else {
  530. scaleX = 1.0 / Units.EMU_PER_POINT;
  531. }
  532. if (p.getH() != -1) {
  533. scaleY = anchor.getHeight() / p.getH();
  534. } else {
  535. scaleY = 1.0 / Units.EMU_PER_POINT;
  536. }
  537. at.scale(scaleX, scaleY);
  538. Shape canvasShape = at.createTransformedShape(gp);
  539. lst.add(new Outline(canvasShape, p));
  540. }
  541. return lst;
  542. }
  543. public Rectangle2D getAnchor(Graphics2D graphics) {
  544. Rectangle2D anchor = _shape.getAnchor();
  545. if(graphics == null) {
  546. return anchor;
  547. }
  548. AffineTransform tx = (AffineTransform)graphics.getRenderingHint(XSLFRenderingHint.GROUP_TRANSFORM);
  549. if(tx != null) {
  550. anchor = tx.createTransformedShape(anchor).getBounds2D();
  551. }
  552. return anchor;
  553. }
  554. }