git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1906248 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_4
@@ -30,6 +30,7 @@ import org.apache.poi.ooxml.util.POIXMLUnits; | |||
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.sl.draw.DrawPaint; | |||
import org.apache.poi.sl.usermodel.HighlightColorSupport; | |||
import org.apache.poi.sl.usermodel.PaintStyle; | |||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | |||
import org.apache.poi.sl.usermodel.TextRun; | |||
@@ -40,10 +41,12 @@ import org.apache.poi.xslf.model.CharacterPropertyFetcher; | |||
import org.apache.poi.xslf.model.CharacterPropertyFetcher.CharPropFetcher; | |||
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; | |||
import org.apache.xmlbeans.XmlObject; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFontCollection; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFontScheme; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; | |||
@@ -55,13 +58,14 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.impl.CTSRgbColorImpl; | |||
/** | |||
* Represents a run of text within the containing text body. The run element is the | |||
* lowest level text separation mechanism within a text body. | |||
*/ | |||
@Beta | |||
public class XSLFTextRun implements TextRun { | |||
public class XSLFTextRun implements TextRun, HighlightColorSupport { | |||
private static final Logger LOG = LogManager.getLogger(XSLFTextRun.class); | |||
private final XmlObject _r; | |||
@@ -158,6 +162,86 @@ public class XSLFTextRun implements TextRun { | |||
} | |||
/** | |||
* Returns the font highlight (background) color for this text run. | |||
* This returns a {@link SolidPaint}, or null if no highlight is set. | |||
* | |||
* @return The font highlight (background) colour associated with the run, null if no highlight. | |||
* | |||
* @see org.apache.poi.sl.draw.DrawPaint#getPaint(java.awt.Graphics2D, PaintStyle) | |||
* @see SolidPaint#getSolidColor() | |||
* @since POI 5.2.4 | |||
*/ | |||
@Override | |||
public PaintStyle getHighlightColor() { | |||
XSLFShape shape = getParagraph().getParentShape(); | |||
final boolean hasPlaceholder = shape.getPlaceholder() != null; | |||
return fetchCharacterProperty((props, highlightColor) -> fetchHighlightColor(props, highlightColor, shape, hasPlaceholder)); | |||
} | |||
private static void fetchHighlightColor(CTTextCharacterProperties props, Consumer<PaintStyle> highlightColor, XSLFShape shape, boolean hasPlaceholder) { | |||
if (props == null) { | |||
return; | |||
} | |||
final CTColor col = props.getHighlight(); | |||
if (col == null) { | |||
return; | |||
} | |||
final CTSRgbColor rgbCol = col.getSrgbClr(); | |||
final byte[] cols = rgbCol.getVal(); | |||
final SolidPaint paint = DrawPaint.createSolidPaint(new Color(0xFF & cols[0], 0xFF & cols[1], 0xFF & cols[2])); | |||
highlightColor.accept(paint); | |||
} | |||
/** | |||
* Sets the font highlight (background) color for this text run - convenience function | |||
* | |||
* @param color The highlight (background) color to set. | |||
* @since POI 5.2.4 | |||
*/ | |||
@Override | |||
public void setHighlightColor(final Color color) { | |||
setHighlightColor(DrawPaint.createSolidPaint(color)); | |||
} | |||
/** | |||
* Set the highlight (background) color for this text run. | |||
* | |||
* @param color The highlight (background) color to set. | |||
* @throws IllegalArgumentException If the supplied paint style is not null or a SolidPaint. | |||
* | |||
* @see org.apache.poi.sl.draw.DrawPaint#createSolidPaint(Color) | |||
* @since POI 5.2.4 | |||
*/ | |||
@Override | |||
public void setHighlightColor(final PaintStyle color) { | |||
if (color == null) { | |||
final CTTextCharacterProperties rPr = getRPr(true); | |||
if (rPr.isSetHighlight()) { | |||
rPr.unsetHighlight(); | |||
} | |||
return; | |||
} | |||
if (!(color instanceof SolidPaint)) { | |||
throw new IllegalArgumentException("Currently only SolidPaint is supported!"); | |||
} | |||
final SolidPaint sp = (SolidPaint)color; | |||
final Color c = DrawPaint.applyColorTransform(sp.getSolidColor()); | |||
final CTTextCharacterProperties rPr = getRPr(true); | |||
final CTColor highlight = rPr.isSetHighlight() ? rPr.getHighlight() : rPr.addNewHighlight(); | |||
final CTSRgbColor col = CTSRgbColor.Factory.newInstance(); | |||
col.setVal(new byte[] {(byte)c.getRed(), (byte)c.getGreen(), (byte)c.getBlue()}); | |||
highlight.setSrgbClr(col); | |||
} | |||
@Override | |||
public void setFontSize(Double fontSize){ |
@@ -19,6 +19,7 @@ package org.apache.poi.xslf.usermodel; | |||
import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor; | |||
import static org.junit.jupiter.api.Assertions.assertEquals; | |||
import static org.junit.jupiter.api.Assertions.assertFalse; | |||
import static org.junit.jupiter.api.Assertions.assertNotNull; | |||
import static org.junit.jupiter.api.Assertions.assertNull; | |||
import static org.junit.jupiter.api.Assertions.assertThrows; | |||
import static org.junit.jupiter.api.Assertions.assertTrue; | |||
@@ -26,16 +27,22 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; | |||
import java.awt.Color; | |||
import java.awt.Graphics2D; | |||
import java.awt.font.TextAttribute; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.io.IOException; | |||
import java.text.AttributedCharacterIterator; | |||
import java.text.CharacterIterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.commons.io.output.NullPrintStream; | |||
import org.apache.poi.sl.draw.DrawTextFragment; | |||
import org.apache.poi.sl.draw.DrawTextParagraph; | |||
import org.apache.poi.sl.usermodel.AutoNumberingScheme; | |||
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; | |||
import org.apache.poi.xslf.XSLFTestDataSamples; | |||
import org.apache.poi.xslf.util.DummyGraphics2d; | |||
import org.junit.jupiter.api.Test; | |||
class TestXSLFTextParagraph { | |||
@@ -427,4 +434,65 @@ class TestXSLFTextParagraph { | |||
assertThrows(IllegalStateException.class, () -> r2.setText("aaa")); | |||
} | |||
} | |||
@Test | |||
void testHighlightRender() throws IOException { | |||
try (XMLSlideShow ppt = new XMLSlideShow()) { | |||
XSLFSlide slide = ppt.createSlide(); | |||
XSLFTextShape sh = slide.createAutoShape(); | |||
XSLFTextParagraph p = sh.addNewTextParagraph(); | |||
XSLFTextRun r1 = p.addNewTextRun(); | |||
r1.setText("This is a "); | |||
XSLFTextRun r2 = p.addNewTextRun(); | |||
r2.setText("highlight"); | |||
r2.setHighlightColor(Color.yellow); | |||
XSLFTextRun r3 = p.addNewTextRun(); | |||
r3.setText(" test"); | |||
assertEquals("This is a highlight test", sh.getText()); | |||
DummyGraphics2d dgfx = new DummyGraphics2d(new NullPrintStream()) { | |||
@Override | |||
public void drawString(AttributedCharacterIterator iterator, float x, float y) { | |||
// For the test file, common sl draws textruns one by one and not mixed | |||
// so we evaluate the whole iterator | |||
Map<AttributedCharacterIterator.Attribute, Object> attributes = null; | |||
StringBuilder sb = new StringBuilder(); | |||
for (char c = iterator.first(); | |||
c != CharacterIterator.DONE; | |||
c = iterator.next()) { | |||
sb.append(c); | |||
attributes = iterator.getAttributes(); | |||
} | |||
if ("This is a".equals(sb.toString())) { | |||
// Should be no background. | |||
assertNotNull(attributes); | |||
Object background = attributes.get(TextAttribute.BACKGROUND); | |||
assertNull(background); | |||
} | |||
if ("highlight".equals(sb.toString())) { | |||
// Should be yellow background. | |||
assertNotNull(attributes); | |||
Object background = attributes.get(TextAttribute.BACKGROUND); | |||
assertNotNull(background); | |||
assertTrue(background instanceof Color); | |||
assertEquals(Color.yellow, background); | |||
} | |||
if (" test".equals(sb.toString())) { | |||
// Should be no background. | |||
assertNotNull(attributes); | |||
Object background = attributes.get(TextAttribute.BACKGROUND); | |||
assertNull(background); | |||
} | |||
} | |||
}; | |||
ppt.getSlides().get(0).draw(dgfx); | |||
} | |||
} | |||
} |
@@ -23,15 +23,26 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | |||
import static org.junit.jupiter.api.Assertions.assertEquals; | |||
import static org.junit.jupiter.api.Assertions.assertFalse; | |||
import static org.junit.jupiter.api.Assertions.assertNotEquals; | |||
import static org.junit.jupiter.api.Assertions.assertNull; | |||
import static org.junit.jupiter.api.Assertions.assertTrue; | |||
import static org.junit.jupiter.api.Assertions.fail; | |||
import java.awt.Color; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import org.apache.poi.POIDataSamples; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.sl.draw.DrawPaint; | |||
import org.apache.poi.sl.draw.DrawTextParagraph; | |||
import org.apache.poi.sl.usermodel.PaintStyle; | |||
import org.apache.poi.xslf.model.PropertyFetcher; | |||
import org.junit.jupiter.api.Test; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | |||
@@ -80,6 +91,32 @@ class TestXSLFTextRun { | |||
r.setSubscript(false); | |||
assertFalse(r.isSubscript()); | |||
// Test highlight get/set. | |||
assertNull(r.getHighlightColor()); | |||
r.setHighlightColor(Color.yellow); | |||
assertEquals(DrawPaint.createSolidPaint(Color.yellow), r.getHighlightColor()); | |||
r.setHighlightColor(DrawPaint.createSolidPaint(Color.blue)); | |||
assertEquals(DrawPaint.createSolidPaint(Color.blue), r.getHighlightColor()); | |||
r.setHighlightColor((Color) null); | |||
assertNull(r.getHighlightColor()); | |||
r.setHighlightColor((PaintStyle) null); | |||
assertNull(r.getHighlightColor()); | |||
try { | |||
// make a dummy gradient to test paint rejection. | |||
final XSLFSheet sheet = sh.getSheet(); | |||
final XSLFTheme theme = sheet.getTheme(); | |||
final CTSchemeColor phClr = CTSchemeColor.Factory.newInstance(); | |||
final CTGradientFillProperties gradFill = CTGradientFillProperties.Factory.newInstance(); | |||
final XSLFGradientPaint dummyGrad = new XSLFGradientPaint(gradFill, phClr, theme, sheet); | |||
r.setHighlightColor(dummyGrad); | |||
fail("Expected non solid paint to cause an exception."); | |||
} catch (IllegalArgumentException iae) { | |||
// Expected, do nothing. | |||
} | |||
ppt.close(); | |||
} | |||
@@ -545,6 +545,7 @@ public final class TestTextRun { | |||
} | |||
} | |||
@Test | |||
void testAppendEmpty() throws IOException { | |||
try (HSLFSlideShow ppt = new HSLFSlideShow()) { |
@@ -47,6 +47,7 @@ import org.apache.poi.common.usermodel.fonts.FontGroup; | |||
import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange; | |||
import org.apache.poi.common.usermodel.fonts.FontInfo; | |||
import org.apache.poi.sl.usermodel.AutoNumberingScheme; | |||
import org.apache.poi.sl.usermodel.HighlightColorSupport; | |||
import org.apache.poi.sl.usermodel.Hyperlink; | |||
import org.apache.poi.sl.usermodel.Insets2D; | |||
import org.apache.poi.sl.usermodel.PaintStyle; | |||
@@ -65,6 +66,7 @@ import org.apache.poi.util.Internal; | |||
import org.apache.poi.util.LocaleUtil; | |||
import org.apache.poi.util.StringUtil; | |||
import org.apache.poi.util.Units; | |||
import org.w3c.dom.Text; | |||
public class DrawTextParagraph implements Drawable { | |||
private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class); | |||
@@ -610,6 +612,15 @@ public class DrawTextParagraph implements Drawable { | |||
att.put(TextAttribute.FOREGROUND, fgPaint); | |||
if (run instanceof HighlightColorSupport) { | |||
// Highlight color is only supported in XSLF (PPTX) text runs. | |||
final PaintStyle highlightPaintStyle = ((HighlightColorSupport)run).getHighlightColor(); | |||
if (highlightPaintStyle != null) { | |||
final Paint bgPaint = dp.getPaint(graphics, highlightPaintStyle); | |||
att.put(TextAttribute.BACKGROUND, bgPaint); | |||
} | |||
} | |||
Double fontSz = run.getFontSize(); | |||
if (fontSz == null) { | |||
fontSz = paragraph.getDefaultFontSize(); |
@@ -29,6 +29,7 @@ import org.apache.poi.util.Internal; | |||
*/ | |||
@SuppressWarnings({"unused","java:S1452"}) | |||
public interface TextRun { | |||
/** | |||
* Type of text capitals | |||
*/ | |||
@@ -78,7 +79,6 @@ public interface TextRun { | |||
*/ | |||
void setFontColor(PaintStyle color); | |||
/** | |||
* Returns the font size which is either set directly on this text run or | |||
* given from the slide layout |