Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

XSLFShape.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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.awt.Graphics2D;
  21. import java.awt.geom.Rectangle2D;
  22. import java.util.Locale;
  23. import javax.xml.namespace.QName;
  24. import javax.xml.stream.XMLStreamReader;
  25. import com.microsoft.schemas.compatibility.AlternateContentDocument;
  26. import com.microsoft.schemas.compatibility.AlternateContentDocument.AlternateContent;
  27. import org.apache.poi.openxml4j.opc.PackagePart;
  28. import org.apache.poi.sl.draw.DrawFactory;
  29. import org.apache.poi.sl.draw.DrawPaint;
  30. import org.apache.poi.sl.usermodel.MasterSheet;
  31. import org.apache.poi.sl.usermodel.PaintStyle;
  32. import org.apache.poi.sl.usermodel.PlaceableShape;
  33. import org.apache.poi.sl.usermodel.Placeholder;
  34. import org.apache.poi.sl.usermodel.PlaceholderDetails;
  35. import org.apache.poi.sl.usermodel.Shape;
  36. import org.apache.poi.sl.usermodel.SimpleShape;
  37. import org.apache.poi.util.Beta;
  38. import org.apache.poi.util.Internal;
  39. import org.apache.poi.xslf.model.PropertyFetcher;
  40. import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
  41. import org.apache.xmlbeans.XmlCursor;
  42. import org.apache.xmlbeans.XmlException;
  43. import org.apache.xmlbeans.XmlObject;
  44. import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
  45. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
  46. import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
  47. import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
  48. import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
  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.CTStyleMatrix;
  54. import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
  55. import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
  56. import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
  57. import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
  58. import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
  59. import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
  60. import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
  61. /**
  62. * Base super-class class for all shapes in PresentationML
  63. */
  64. @Beta
  65. public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
  66. @Internal
  67. public interface ReparseFactory<T extends XmlObject> {
  68. T parse(XMLStreamReader reader) throws XmlException;
  69. }
  70. static final String DML_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
  71. static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main";
  72. private static final String MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
  73. private static final String MAC_DML_NS = "http://schemas.microsoft.com/office/mac/drawingml/2008/main";
  74. private static final QName ALTERNATE_CONTENT_TAG = new QName(MC_NS, "AlternateContent");
  75. private static final QName[] NV_CONTAINER = {
  76. new QName(PML_NS, "nvSpPr"),
  77. new QName(PML_NS, "nvCxnSpPr"),
  78. new QName(PML_NS, "nvGrpSpPr"),
  79. new QName(PML_NS, "nvPicPr"),
  80. new QName(PML_NS, "nvGraphicFramePr")
  81. };
  82. private static final QName[] CNV_PROPS = {
  83. new QName(PML_NS, "cNvPr")
  84. };
  85. private static final String OSGI_ERROR =
  86. "Schemas (*.xsb) for <CLASS> can't be loaded - usually this happens when OSGI " +
  87. "loading is used and the thread context classloader has no reference to " +
  88. "the xmlbeans classes - please either verify if the <XSB>.xsb is on the " +
  89. "classpath or alternatively try to use the full ooxml-schemas-x.x.jar";
  90. private final XmlObject _shape;
  91. private final XSLFSheet _sheet;
  92. private XSLFShapeContainer _parent;
  93. private CTShapeStyle _spStyle;
  94. private CTNonVisualDrawingProps _nvPr;
  95. protected XSLFShape(XmlObject shape, XSLFSheet sheet) {
  96. _shape = shape;
  97. _sheet = sheet;
  98. }
  99. /**
  100. * @return the xml bean holding this shape's data
  101. */
  102. public final XmlObject getXmlObject() {
  103. // it's final because the xslf inheritance hierarchy is not necessary the same as
  104. // the (not existing) xmlbeans hierarchy and subclasses shouldn't narrow it's return value
  105. return _shape;
  106. }
  107. @Override
  108. public XSLFSheet getSheet() {
  109. return _sheet;
  110. }
  111. @Override
  112. public String getShapeName() {
  113. CTNonVisualDrawingProps nonVisualDrawingProps = getCNvPr();
  114. return nonVisualDrawingProps == null ? null : nonVisualDrawingProps.getName();
  115. }
  116. @Override
  117. public int getShapeId() {
  118. CTNonVisualDrawingProps nonVisualDrawingProps = getCNvPr();
  119. if (nonVisualDrawingProps == null) {
  120. throw new IllegalStateException("no underlying shape exists");
  121. }
  122. return Math.toIntExact(nonVisualDrawingProps.getId());
  123. }
  124. /**
  125. * Set the contents of this shape to be a copy of the source shape.
  126. * This method is called recursively for each shape when merging slides
  127. *
  128. * @param sh the source shape
  129. * @see org.apache.poi.xslf.usermodel.XSLFSlide#importContent(XSLFSheet)
  130. */
  131. @Internal
  132. void copy(XSLFShape sh) {
  133. if (!getClass().isInstance(sh)) {
  134. throw new IllegalArgumentException(
  135. "Can't copy " + sh.getClass().getSimpleName() + " into " + getClass().getSimpleName());
  136. }
  137. if (this instanceof PlaceableShape) {
  138. PlaceableShape<?,?> ps = (PlaceableShape<?,?>)this;
  139. ps.setAnchor(sh.getAnchor());
  140. }
  141. }
  142. public void setParent(XSLFShapeContainer parent) {
  143. this._parent = parent;
  144. }
  145. @Override
  146. public XSLFShapeContainer getParent() {
  147. return this._parent;
  148. }
  149. protected PaintStyle getFillPaint() {
  150. final XSLFTheme theme = getSheet().getTheme();
  151. final boolean hasPlaceholder = getPlaceholder() != null;
  152. PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
  153. @Override
  154. public boolean fetch(XSLFShape shape) {
  155. PackagePart pp = shape.getSheet().getPackagePart();
  156. if (shape instanceof XSLFPictureShape) {
  157. CTPicture pic = (CTPicture)shape.getXmlObject();
  158. if (pic.getBlipFill() != null) {
  159. setValue(selectPaint(pic.getBlipFill(), pp, null, theme));
  160. return true;
  161. }
  162. }
  163. XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(shape.getShapeProperties());
  164. if (fp == null) {
  165. return false;
  166. }
  167. if (fp.isSetNoFill()) {
  168. setValue(null);
  169. return true;
  170. }
  171. PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
  172. if (paint != null) {
  173. setValue(paint);
  174. return true;
  175. }
  176. CTShapeStyle style = shape.getSpStyle();
  177. if (style != null) {
  178. fp = XSLFPropertiesDelegate.getFillDelegate(style.getFillRef());
  179. paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
  180. }
  181. if (paint != null) {
  182. setValue(paint);
  183. return true;
  184. }
  185. return false;
  186. }
  187. };
  188. fetchShapeProperty(fetcher);
  189. return fetcher.getValue();
  190. }
  191. @SuppressWarnings("unused")
  192. protected CTBackgroundProperties getBgPr() {
  193. return getChild(CTBackgroundProperties.class, PML_NS, "bgPr");
  194. }
  195. @SuppressWarnings("unused")
  196. protected CTStyleMatrixReference getBgRef() {
  197. return getChild(CTStyleMatrixReference.class, PML_NS, "bgRef");
  198. }
  199. protected CTGroupShapeProperties getGrpSpPr() {
  200. return getChild(CTGroupShapeProperties.class, PML_NS, "grpSpPr");
  201. }
  202. protected CTNonVisualDrawingProps getCNvPr() {
  203. try {
  204. if (_nvPr == null) {
  205. _nvPr = selectProperty(CTNonVisualDrawingProps.class, null, NV_CONTAINER, CNV_PROPS);
  206. }
  207. return _nvPr;
  208. } catch (XmlException e) {
  209. return null;
  210. }
  211. }
  212. @SuppressWarnings("WeakerAccess")
  213. protected CTShapeStyle getSpStyle() {
  214. if (_spStyle == null) {
  215. _spStyle = getChild(CTShapeStyle.class, PML_NS, "style");
  216. }
  217. return _spStyle;
  218. }
  219. /**
  220. * Return direct child objects of this shape
  221. *
  222. * @param childClass the class to cast the properties to
  223. * @param namespace the namespace - usually it is {@code "http://schemas.openxmlformats.org/presentationml/2006/main"}
  224. * @param nodename the node name, without prefix
  225. * @return the properties object or null if it can't be found
  226. */
  227. @SuppressWarnings({"unchecked", "WeakerAccess", "unused", "SameParameterValue"})
  228. protected <T extends XmlObject> T getChild(Class<T> childClass, String namespace, String nodename) {
  229. XmlCursor cur = getXmlObject().newCursor();
  230. T child = null;
  231. if (cur.toChild(namespace, nodename)) {
  232. child = (T)cur.getObject();
  233. }
  234. if (cur.toChild(XSLFRelation.NS_DRAWINGML, nodename)) {
  235. child = (T)cur.getObject();
  236. }
  237. cur.dispose();
  238. return child;
  239. }
  240. public boolean isPlaceholder() {
  241. return getPlaceholderDetails().getCTPlaceholder(false) != null;
  242. }
  243. /**
  244. * @see PlaceholderDetails#getPlaceholder()
  245. */
  246. public Placeholder getPlaceholder() {
  247. return getPlaceholderDetails().getPlaceholder();
  248. }
  249. /**
  250. * @see PlaceholderDetails#setPlaceholder(Placeholder)
  251. */
  252. public void setPlaceholder(final Placeholder placeholder) {
  253. getPlaceholderDetails().setPlaceholder(placeholder);
  254. }
  255. /**
  256. * @see SimpleShape#getPlaceholderDetails()
  257. */
  258. @SuppressWarnings("WeakerAccess")
  259. public XSLFPlaceholderDetails getPlaceholderDetails() {
  260. return new XSLFPlaceholderDetails(this);
  261. }
  262. /**
  263. * As there's no xmlbeans hierarchy, but XSLF works with subclassing, not all
  264. * child classes work with a {@link CTShape} object, but often contain the same
  265. * properties. This method is the generalized form of selecting and casting those
  266. * properties.
  267. *
  268. * @param resultClass the requested result class
  269. * @param xquery the simple (xmlbean) xpath expression to the property
  270. * @return the xml object at the xpath location, or null if not found
  271. */
  272. @SuppressWarnings({"unchecked", "WeakerAccess"})
  273. protected <T extends XmlObject> T selectProperty(Class<T> resultClass, String xquery) {
  274. XmlObject[] rs = getXmlObject().selectPath(xquery);
  275. if (rs.length == 0) {
  276. return null;
  277. }
  278. return (resultClass.isInstance(rs[0])) ? (T)rs[0] : null;
  279. }
  280. /**
  281. * Internal code - API may change any time!
  282. * <p>
  283. * The {@link #selectProperty(Class, String)} xquery method has some performance penalties,
  284. * which can be workaround by using {@link XmlCursor}. This method also takes into account
  285. * that {@code AlternateContent} tags can occur anywhere on the given path.
  286. * <p>
  287. * It returns the first element found - the search order is:
  288. * <ul>
  289. * <li>searching for a direct child</li>
  290. * <li>searching for a AlternateContent.Choice child</li>
  291. * <li>searching for a AlternateContent.Fallback child</li>
  292. * </ul>
  293. * Currently POI OOXML is based on the first edition of the ECMA 376 schema, which doesn't
  294. * allow AlternateContent tags to show up everywhere. The factory flag is
  295. * a workaround to process files based on a later edition. But it comes with the drawback:
  296. * any change on the returned XmlObject aren't saved back to the underlying document -
  297. * so it's a non updatable clone. If factory is null, a XmlException is
  298. * thrown if the AlternateContent is not allowed by the surrounding element or if the
  299. * extracted object is of the generic type XmlAnyTypeImpl.
  300. *
  301. * @param resultClass the requested result class
  302. * @param factory a factory parse method reference to allow reparsing of elements
  303. * extracted from AlternateContent elements. Usually the enclosing XmlBeans type needs to be used
  304. * to parse the stream
  305. * @param path the elements path, each array must contain at least 1 QName,
  306. * but can contain additional alternative tags
  307. * @return the xml object at the path location, or null if not found
  308. *
  309. * @throws XmlException If factory is null, a XmlException is
  310. * thrown if the AlternateContent is not allowed by the surrounding element or if the
  311. * extracted object is of the generic type XmlAnyTypeImpl.
  312. *
  313. * @since POI 4.1.2
  314. */
  315. @SuppressWarnings("unchecked")
  316. @Internal
  317. public <T extends XmlObject> T selectProperty(Class<T> resultClass, ReparseFactory<T> factory, QName[]... path)
  318. throws XmlException {
  319. XmlObject xo = getXmlObject();
  320. XmlCursor cur = xo.newCursor();
  321. XmlCursor innerCur = null;
  322. try {
  323. innerCur = selectProperty(cur, path, 0, factory != null, false);
  324. if (innerCur == null) {
  325. return null;
  326. }
  327. // Pesky XmlBeans bug - see Bugzilla #49934
  328. // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
  329. xo = innerCur.getObject();
  330. if (xo instanceof XmlAnyTypeImpl) {
  331. String errorTxt = OSGI_ERROR
  332. .replace("<CLASS>", resultClass.getSimpleName())
  333. .replace("<XSB>", resultClass.getSimpleName().toLowerCase(Locale.ROOT)+"*");
  334. if (factory == null) {
  335. throw new XmlException(errorTxt);
  336. } else {
  337. xo = factory.parse(innerCur.newXMLStreamReader());
  338. }
  339. }
  340. return (T)xo;
  341. } finally {
  342. cur.dispose();
  343. if (innerCur != null) {
  344. innerCur.dispose();
  345. }
  346. }
  347. }
  348. private XmlCursor selectProperty(final XmlCursor cur, final QName[][] path, final int offset, final boolean reparseAlternate, final boolean isAlternate)
  349. throws XmlException {
  350. // first try the direct children
  351. for (QName qn : path[offset]) {
  352. if (cur.toChild(qn)) {
  353. if (offset == path.length-1) {
  354. return cur;
  355. }
  356. cur.push();
  357. XmlCursor innerCur = selectProperty(cur, path, offset+1, reparseAlternate, false);
  358. if (innerCur != null) {
  359. return innerCur;
  360. }
  361. cur.pop();
  362. }
  363. }
  364. // if we were called inside an alternate content handling don't look for alternates again
  365. if (isAlternate || !cur.toChild(ALTERNATE_CONTENT_TAG)) {
  366. return null;
  367. }
  368. // otherwise check first the choice then the fallback content
  369. XmlObject xo = cur.getObject();
  370. AlternateContent alterCont;
  371. if (xo instanceof AlternateContent) {
  372. alterCont = (AlternateContent)xo;
  373. } else {
  374. // Pesky XmlBeans bug - see Bugzilla #49934
  375. // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
  376. if (!reparseAlternate) {
  377. throw new XmlException(OSGI_ERROR
  378. .replace("<CLASS>", "AlternateContent")
  379. .replace("<XSB>", "alternatecontentelement")
  380. );
  381. }
  382. try {
  383. AlternateContentDocument acd = AlternateContentDocument.Factory.parse(cur.newXMLStreamReader());
  384. alterCont = acd.getAlternateContent();
  385. } catch (XmlException e) {
  386. throw new XmlException("unable to parse AlternateContent element", e);
  387. }
  388. }
  389. final int choices = alterCont.sizeOfChoiceArray();
  390. for (int i=0; i<choices; i++) {
  391. // TODO: check [Requires] attribute of [Choice] element, if we can handle the content
  392. AlternateContent.Choice choice = alterCont.getChoiceArray(i);
  393. XmlCursor cCur = choice.newCursor();
  394. XmlCursor innerCur = null;
  395. try {
  396. String requiresNS = cCur.namespaceForPrefix(choice.getRequires());
  397. if (MAC_DML_NS.equalsIgnoreCase(requiresNS)) {
  398. // Mac DML usually contains PDFs ...
  399. continue;
  400. }
  401. innerCur = selectProperty(cCur, path, offset, reparseAlternate, true);
  402. if (innerCur != null) {
  403. return innerCur;
  404. }
  405. } finally {
  406. if (innerCur != cCur) {
  407. cCur.dispose();
  408. }
  409. }
  410. }
  411. if (!alterCont.isSetFallback()) {
  412. return null;
  413. }
  414. XmlCursor fCur = alterCont.getFallback().newCursor();
  415. XmlCursor innerCur = null;
  416. try {
  417. innerCur = selectProperty(fCur, path, offset, reparseAlternate, true);
  418. return innerCur;
  419. } finally {
  420. if (innerCur != fCur) {
  421. fCur.dispose();
  422. }
  423. }
  424. }
  425. /**
  426. * Walk up the inheritance tree and fetch shape properties.<p>
  427. *
  428. * The following order of inheritance is assumed:<p>
  429. * <ol>
  430. * <li>slide
  431. * <li>slideLayout
  432. * <li>slideMaster
  433. * </ol>
  434. *
  435. * Currently themes and their defaults aren't correctly handled
  436. *
  437. * @param visitor the object that collects the desired property
  438. * @return true if the property was fetched
  439. */
  440. @SuppressWarnings("WeakerAccess")
  441. @Internal
  442. public boolean fetchShapeProperty(PropertyFetcher<?> visitor) {
  443. // try shape properties in slide
  444. if (visitor.fetch(this)) {
  445. return true;
  446. }
  447. final CTPlaceholder ph = getPlaceholderDetails().getCTPlaceholder(false);
  448. if (ph == null) {
  449. return false;
  450. }
  451. MasterSheet<XSLFShape,XSLFTextParagraph> sm = getSheet().getMasterSheet();
  452. // try slide layout
  453. if (sm instanceof XSLFSlideLayout) {
  454. XSLFSlideLayout slideLayout = (XSLFSlideLayout)sm;
  455. XSLFSimpleShape placeholderShape = slideLayout.getPlaceholder(ph);
  456. if (placeholderShape != null && visitor.fetch(placeholderShape)) {
  457. return true;
  458. }
  459. sm = slideLayout.getMasterSheet();
  460. }
  461. // try slide master
  462. if (sm instanceof XSLFSlideMaster) {
  463. XSLFSlideMaster master = (XSLFSlideMaster)sm;
  464. int textType = getPlaceholderType(ph);
  465. XSLFSimpleShape masterShape = master.getPlaceholderByType(textType);
  466. return masterShape != null && visitor.fetch(masterShape);
  467. }
  468. return false;
  469. }
  470. private static int getPlaceholderType(CTPlaceholder ph) {
  471. if ( !ph.isSetType()) {
  472. return STPlaceholderType.INT_BODY;
  473. }
  474. switch (ph.getType().intValue()) {
  475. case STPlaceholderType.INT_TITLE:
  476. case STPlaceholderType.INT_CTR_TITLE:
  477. return STPlaceholderType.INT_TITLE;
  478. case STPlaceholderType.INT_FTR:
  479. case STPlaceholderType.INT_SLD_NUM:
  480. case STPlaceholderType.INT_DT:
  481. return ph.getType().intValue();
  482. default:
  483. return STPlaceholderType.INT_BODY;
  484. }
  485. }
  486. /**
  487. * Convert shape fill into java.awt.Paint. The result is either Color or
  488. * TexturePaint or GradientPaint or null
  489. *
  490. * @param fp a properties handler specific to the underlying shape properties
  491. * @param phClr context color
  492. * @param parentPart the parent package part. Any external references (images, etc.) are resolved relative to it.
  493. * @param theme the theme for the shape/sheet
  494. *
  495. * @return the applied Paint or null if none was applied
  496. */
  497. @SuppressWarnings("WeakerAccess")
  498. protected PaintStyle selectPaint(XSLFFillProperties fp, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme, boolean hasPlaceholder) {
  499. if (fp == null || fp.isSetNoFill()) {
  500. return null;
  501. } else if (fp.isSetSolidFill()) {
  502. return selectPaint(fp.getSolidFill(), phClr, theme);
  503. } else if (fp.isSetBlipFill()) {
  504. return selectPaint(fp.getBlipFill(), parentPart, phClr, theme);
  505. } else if (fp.isSetGradFill()) {
  506. return selectPaint(fp.getGradFill(), phClr, theme);
  507. } else if (fp.isSetMatrixStyle()) {
  508. return selectPaint(fp.getMatrixStyle(), theme, fp.isLineStyle(), hasPlaceholder);
  509. } else if (phClr != null) {
  510. return selectPaint(phClr, theme);
  511. } else {
  512. return null;
  513. }
  514. }
  515. protected PaintStyle selectPaint(CTSchemeColor phClr, final XSLFTheme theme) {
  516. final XSLFColor c = new XSLFColor(null, theme, phClr, _sheet);
  517. return DrawPaint.createSolidPaint(c.getColorStyle());
  518. }
  519. @SuppressWarnings("WeakerAccess")
  520. protected PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) {
  521. CTSchemeColor nestedPhClr = solidFill.getSchemeClr();
  522. boolean useNested = nestedPhClr != null && nestedPhClr.getVal() != null && !STSchemeColorVal.PH_CLR.equals(nestedPhClr.getVal());
  523. final XSLFColor c = new XSLFColor(solidFill, theme, useNested ? nestedPhClr : phClr, _sheet);
  524. return DrawPaint.createSolidPaint(c.getColorStyle());
  525. }
  526. @SuppressWarnings("WeakerAccess")
  527. protected PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart, CTSchemeColor phClr, final XSLFTheme theme) {
  528. return new XSLFTexturePaint(blipFill, parentPart, phClr, theme, _sheet);
  529. }
  530. @SuppressWarnings("WeakerAccess")
  531. protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) {
  532. return new XSLFGradientPaint(gradFill, phClr, theme, _sheet);
  533. }
  534. @SuppressWarnings("WeakerAccess")
  535. protected PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle, boolean hasPlaceholder) {
  536. if (fillRef == null) {
  537. return null;
  538. }
  539. // The idx attribute refers to the index of a fill style or
  540. // background fill style within the presentation's style matrix, defined by the fmtScheme element.
  541. // value of 0 or 1000 indicates no background,
  542. // values 1-999 refer to the index of a fill style within the fillStyleLst element
  543. // values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
  544. long idx = fillRef.getIdx();
  545. CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();
  546. final XmlObject styleLst;
  547. long childIdx;
  548. if (idx >= 1 && idx <= 999) {
  549. childIdx = idx-1;
  550. styleLst = (isLineStyle) ? matrix.getLnStyleLst() : matrix.getFillStyleLst();
  551. } else if (idx >= 1001 ){
  552. childIdx = idx - 1001;
  553. styleLst = matrix.getBgFillStyleLst();
  554. } else {
  555. return null;
  556. }
  557. XmlCursor cur = styleLst.newCursor();
  558. XSLFFillProperties fp = null;
  559. if (cur.toChild(Math.toIntExact(childIdx))) {
  560. fp = XSLFPropertiesDelegate.getFillDelegate(cur.getObject());
  561. }
  562. cur.dispose();
  563. CTSchemeColor phClr = fillRef.getSchemeClr();
  564. PaintStyle res = selectPaint(fp, phClr, theme.getPackagePart(), theme, hasPlaceholder);
  565. // check for empty placeholder value
  566. // see http://officeopenxml.com/prSlide-color.php - "Color Placeholders within Themes"
  567. if (res != null || hasPlaceholder) {
  568. return res;
  569. }
  570. XSLFColor col = new XSLFColor(fillRef, theme, phClr, _sheet);
  571. return DrawPaint.createSolidPaint(col.getColorStyle());
  572. }
  573. @Override
  574. public void draw(Graphics2D graphics, Rectangle2D bounds) {
  575. DrawFactory.getInstance(graphics).drawShape(graphics, this, bounds);
  576. }
  577. /**
  578. * Return the shape specific (visual) properties
  579. *
  580. * @return the shape specific properties
  581. */
  582. protected XmlObject getShapeProperties() {
  583. return getChild(CTShapeProperties.class, PML_NS, "spPr");
  584. }
  585. }