Rendering fixes

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1686117 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-06-17 22:21:13 +00:00
parent 2170a52383
commit f97d6f6c34
22 changed files with 1192 additions and 1197 deletions

View File

@ -39,8 +39,8 @@ public final class BulletsDemo {
HSLFTextParagraph rt = shape.getTextParagraphs().get(0);
rt.getTextRuns().get(0).setFontSize(42);
rt.setBullet(true);
rt.setIndent(0); //bullet offset
rt.setLeftMargin(50); //text offset (should be greater than bullet offset)
rt.setIndent(0d); //bullet offset
rt.setLeftMargin(50d); //text offset (should be greater than bullet offset)
rt.setBulletChar('\u263A'); //bullet character
shape.setText(
"January\r" +

View File

@ -48,8 +48,8 @@ public class Tutorial2 {
XSLFTextParagraph p2 = shape1.addNewTextParagraph();
// If spaceBefore >= 0, then space is a percentage of normal line height.
// If spaceBefore < 0, the absolute value of linespacing is the spacing in points
p2.setSpaceBefore(-20); // 20 pt from the previous paragraph
p2.setSpaceAfter(300); // 3 lines after the paragraph
p2.setSpaceBefore(-20d); // 20 pt from the previous paragraph
p2.setSpaceAfter(300d); // 3 lines after the paragraph
XSLFTextRun r2 = p2.addNewTextRun();
r2.setText("Paragraph properties apply to all text residing within the corresponding paragraph.");
r2.setFontSize(16);
@ -62,8 +62,8 @@ public class Tutorial2 {
r3.setFontColor(new Color(85, 142, 213));
XSLFTextParagraph p4 = shape1.addNewTextParagraph();
p4.setSpaceBefore(-20); // 20 pt from the previous paragraph
p4.setSpaceAfter(300); // 3 lines after the paragraph
p4.setSpaceBefore(-20d); // 20 pt from the previous paragraph
p4.setSpaceAfter(300d); // 3 lines after the paragraph
XSLFTextRun r4 = p4.addNewTextRun();
r4.setFontSize(16);
r4.setText(

View File

@ -45,9 +45,9 @@ public class Tutorial7 {
XSLFTextParagraph p2 = shape.addNewTextParagraph();
// indentation before text
p2.setLeftMargin(60);
p2.setLeftMargin(60d);
// the bullet is set 40 pt before the text
p2.setIndent(-40);
p2.setIndent(-40d);
p2.setBullet(true);
// customize bullets
p2.setBulletFontColor(Color.red);

View File

@ -16,6 +16,8 @@
==================================================================== */
package org.apache.poi.util;
import org.apache.poi.hslf.usermodel.HSLFShape;
/**
* @author Yegor Kozlov
*/
@ -23,6 +25,22 @@ public class Units {
public static final int EMU_PER_PIXEL = 9525;
public static final int EMU_PER_POINT = 12700;
/**
* Master DPI (576 pixels per inch).
* Used by the reference coordinate system in PowerPoint (HSLF)
*/
public static final int MASTER_DPI = 576;
/**
* Pixels DPI (96 pixels per inch)
*/
public static final int PIXEL_DPI = 96;
/**
* Points DPI (72 pixels per inch)
*/
public static final int POINT_DPI = 72;
/**
* Converts points to EMUs
* @param points points
@ -70,4 +88,17 @@ public class Units {
int fixedPoint = (i << 16) | (f & 0xFFFF);
return fixedPoint;
}
public static double masterToPoints(int masterDPI) {
double points = masterDPI;
points *= HSLFShape.POINT_DPI;
points /= HSLFShape.MASTER_DPI;
return points;
}
public static int pointsToMaster(double points) {
points *= HSLFShape.MASTER_DPI;
points /= HSLFShape.POINT_DPI;
return (int)points;
}
}

View File

@ -137,8 +137,10 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
/**
* Returns the alignment that is applied to the paragraph.
*
* If this attribute is omitted, then a value of left is implied.
* @return ??? alignment that is applied to the paragraph
* If this attribute is omitted, then null is returned.
* User code can imply the value {@link TextAlign#LEFT} then.
*
* @return alignment that is applied to the paragraph
*/
public TextAlign getTextAlign(){
ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getLevel()){
@ -152,7 +154,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
};
fetchParagraphProperty(fetcher);
return fetcher.getValue() == null ? TextAlign.LEFT : fetcher.getValue();
return fetcher.getValue();
}
/**
@ -184,7 +186,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
};
fetchParagraphProperty(fetcher);
return fetcher.getValue() == null ? FontAlign.AUTO : fetcher.getValue();
return fetcher.getValue();
}
/**
@ -294,7 +296,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
*
* @return the bullet size
*/
public double getBulletFontSize(){
public Double getBulletFontSize(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetBuSzPct()){
@ -309,7 +311,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
};
fetchParagraphProperty(fetcher);
return fetcher.getValue() == null ? 100 : fetcher.getValue();
return fetcher.getValue();
}
/**
@ -334,27 +336,19 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
}
/**
* Specifies the indent size that will be applied to the first line of text in the paragraph.
*
* @param value the indent in points.
*/
@Override
public void setIndent(double value){
public void setIndent(Double indent){
if (indent == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
if(value == -1) {
if(indent == -1) {
if(pr.isSetIndent()) pr.unsetIndent();
} else {
pr.setIndent(Units.toEMU(value));
pr.setIndent(Units.toEMU(indent));
}
}
/**
*
* @return the indent applied to the first line of text in the paragraph.
*/
@Override
public double getIndent(){
public Double getIndent() {
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
@ -367,32 +361,26 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
};
fetchParagraphProperty(fetcher);
return fetcher.getValue() == null ? 0 : fetcher.getValue();
return fetcher.getValue();
}
/**
* Specifies the left margin of the paragraph. This is specified in addition to the text body
* inset and applies only to this text paragraph. That is the text body Inset and the LeftMargin
* attributes are additive with respect to the text position.
*
* @param value the left margin (in points) of the paragraph
*/
@Override
public void setLeftMargin(double value){
public void setLeftMargin(Double leftMargin){
if (leftMargin == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
if(value == -1) {
if (leftMargin == null) {
if(pr.isSetMarL()) pr.unsetMarL();
} else {
pr.setMarL(Units.toEMU(value));
pr.setMarL(Units.toEMU(leftMargin));
}
}
/**
* @return the left margin (in points) of the paragraph
* @return the left margin (in points) of the paragraph, null if unset
*/
@Override
public double getLeftMargin(){
public Double getLeftMargin(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetMarL()){
@ -405,32 +393,26 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
};
fetchParagraphProperty(fetcher);
// if the marL attribute is omitted, then a value of 347663 is implied
return fetcher.getValue() == null ? 0 : fetcher.getValue();
return fetcher.getValue();
}
/**
* Specifies the right margin of the paragraph. This is specified in addition to the text body
* inset and applies only to this text paragraph. That is the text body Inset and the RightMargin
* attributes are additive with respect to the text position.
*
* @param value the right margin (in points) of the paragraph
*/
@Override
public void setRightMargin(double value){
public void setRightMargin(Double rightMargin){
if (rightMargin == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
if(value == -1) {
if(rightMargin == -1) {
if(pr.isSetMarR()) pr.unsetMarR();
} else {
pr.setMarR(Units.toEMU(value));
pr.setMarR(Units.toEMU(rightMargin));
}
}
/**
*
* @return the right margin of the paragraph
* @return the right margin of the paragraph, null if unset
*/
@Override
public double getRightMargin(){
public Double getRightMargin(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetMarR()){
@ -443,14 +425,11 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
};
fetchParagraphProperty(fetcher);
// if the marL attribute is omitted, then a value of 347663 is implied
return fetcher.getValue() == null ? 0 : fetcher.getValue();
return fetcher.getValue();
}
/**
*
* @return the default size for a tab character within this paragraph in points
*/
public double getDefaultTabSize(){
@Override
public Double getDefaultTabSize(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetDefTabSz()){
@ -462,7 +441,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
};
fetchParagraphProperty(fetcher);
return fetcher.getValue() == null ? 0 : fetcher.getValue();
return fetcher.getValue();
}
public double getTabStop(final int idx){
@ -491,16 +470,25 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
@Override
public void setLineSpacing(double linespacing){
public void setLineSpacing(Double lineSpacing){
if (lineSpacing == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
if(linespacing >= 0) spc.addNewSpcPct().setVal((int)(linespacing*1000));
else spc.addNewSpcPts().setVal((int)(-linespacing*100));
pr.setLnSpc(spc);
if(lineSpacing == null) {
if (pr.isSetLnSpc()) pr.unsetLnSpc();
} else {
CTTextSpacing spc = (pr.isSetLnSpc()) ? pr.getLnSpc() : pr.addNewLnSpc();
if (lineSpacing >= 0) {
(spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct()).setVal((int)(lineSpacing*1000));
if (spc.isSetSpcPts()) spc.unsetSpcPts();
} else {
(spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts()).setVal((int)(-lineSpacing*100));
if (spc.isSetSpcPct()) spc.unsetSpcPct();
}
}
}
@Override
public double getLineSpacing(){
public Double getLineSpacing(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetLnSpc()){
@ -515,8 +503,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
};
fetchParagraphProperty(fetcher);
double lnSpc = fetcher.getValue() == null ? 100 : fetcher.getValue();
if(lnSpc > 0) {
Double lnSpc = fetcher.getValue();
if (lnSpc != null && lnSpc > 0) {
// check if the percentage value is scaled
CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit();
if(normAutofit != null) {
@ -528,26 +516,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
return lnSpc;
}
/**
* Set the amount of vertical white space that will be present before the paragraph.
* This space is specified in either percentage or points:
* <p>
* If spaceBefore >= 0, then space is a percentage of normal line height.
* If spaceBefore < 0, the absolute value of linespacing is the spacing in points
* </p>
* Examples:
* <pre><code>
* // The paragraph will be formatted to have a spacing before the paragraph text.
* // The spacing will be 200% of the size of the largest text on each line
* paragraph.setSpaceBefore(200);
*
* // The spacing will be a size of 48 points
* paragraph.setSpaceBefore(-48.0);
* </code></pre>
*
* @param spaceBefore the vertical white space before the paragraph.
*/
public void setSpaceBefore(double spaceBefore){
@Override
public void setSpaceBefore(Double spaceBefore){
if (spaceBefore == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
if(spaceBefore >= 0) spc.addNewSpcPct().setVal((int)(spaceBefore*1000));
@ -555,17 +526,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
pr.setSpcBef(spc);
}
/**
* The amount of vertical white space before the paragraph
* This may be specified in two different ways, percentage spacing and font point spacing:
* <p>
* If spaceBefore >= 0, then space is a percentage of normal line height.
* If spaceBefore < 0, the absolute value of linespacing is the spacing in points
* </p>
*
* @return the vertical white space before the paragraph
*/
public double getSpaceBefore(){
@Override
public Double getSpaceBefore(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetSpcBef()){
@ -580,30 +542,11 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
};
fetchParagraphProperty(fetcher);
double spcBef = fetcher.getValue() == null ? 0 : fetcher.getValue();
return spcBef;
return fetcher.getValue();
}
/**
* Set the amount of vertical white space that will be present after the paragraph.
* This space is specified in either percentage or points:
* <p>
* If spaceAfter >= 0, then space is a percentage of normal line height.
* If spaceAfter < 0, the absolute value of linespacing is the spacing in points
* </p>
* Examples:
* <pre><code>
* // The paragraph will be formatted to have a spacing after the paragraph text.
* // The spacing will be 200% of the size of the largest text on each line
* paragraph.setSpaceAfter(200);
*
* // The spacing will be a size of 48 points
* paragraph.setSpaceAfter(-48.0);
* </code></pre>
*
* @param spaceAfter the vertical white space after the paragraph.
*/
public void setSpaceAfter(double spaceAfter){
@Override
public void setSpaceAfter(Double spaceAfter){
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
if(spaceAfter >= 0) spc.addNewSpcPct().setVal((int)(spaceAfter*1000));
@ -611,17 +554,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
pr.setSpcAft(spc);
}
/**
* The amount of vertical white space after the paragraph
* This may be specified in two different ways, percentage spacing and font point spacing:
* <p>
* If spaceBefore >= 0, then space is a percentage of normal line height.
* If spaceBefore < 0, the absolute value of linespacing is the spacing in points
* </p>
*
* @return the vertical white space after the paragraph
*/
public double getSpaceAfter(){
@Override
public Double getSpaceAfter(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetSpcAft()){
@ -635,7 +569,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
};
fetchParagraphProperty(fetcher);
return fetcher.getValue() == null ? 0 : fetcher.getValue();
return fetcher.getValue();
}
/**
@ -647,7 +581,6 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
*/
public void setLevel(int level){
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
pr.setLvl(level);
}
@ -657,10 +590,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
*/
public int getLevel(){
CTTextParagraphProperties pr = _p.getPPr();
if(pr == null) return 0;
return pr.getLvl();
return (pr == null || !pr.isSetLvl()) ? 0 : pr.getLvl();
}
/**
@ -721,16 +651,15 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
CTTextParagraphProperties getDefaultMasterStyle(){
/* package */ CTTextParagraphProperties getDefaultMasterStyle(){
CTPlaceholder ph = _shape.getCTPlaceholder();
String defaultStyleSelector;
if(ph == null) defaultStyleSelector = "otherStyle"; // no placeholder means plain text box
else {
switch(ph.getType().intValue()){
switch(ph == null ? -1 : ph.getType().intValue()) {
case STPlaceholderType.INT_TITLE:
case STPlaceholderType.INT_CTR_TITLE:
defaultStyleSelector = "titleStyle";
break;
case -1: // no placeholder means plain text box
case STPlaceholderType.INT_FTR:
case STPlaceholderType.INT_SLD_NUM:
case STPlaceholderType.INT_DT:
@ -740,34 +669,52 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
defaultStyleSelector = "bodyStyle";
break;
}
}
int level = getLevel();
// wind up and find the root master sheet which must be slide master
XSLFSheet masterSheet = _shape.getSheet();
while (masterSheet.getMasterSheet() != null){
masterSheet = (XSLFSheet)masterSheet.getMasterSheet();
for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
masterSheet = m;
}
XmlObject[] o = masterSheet.getXmlObject().selectPath(
String nsDecl =
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr");
if (o.length == 1){
return (CTTextParagraphProperties)o[0];
} else {
o = masterSheet.getXmlObject().selectPath(
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
".//p:notesStyle/a:lvl" +(level+1)+ "pPr");
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' ";
String xpaths[] = {
nsDecl+".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr",
nsDecl+".//p:notesStyle/a:lvl" +(level+1)+ "pPr"
};
XmlObject xo = masterSheet.getXmlObject();
for (String xpath : xpaths) {
XmlObject[] o = xo.selectPath(xpath);
if (o.length == 1) {
return (CTTextParagraphProperties)o[0];
}
throw new IllegalArgumentException("Failed to fetch default style for " +
defaultStyleSelector + " and level=" + level);
}
// for (CTTextBody txBody : (CTTextBody[])xo.selectPath(nsDecl+".//p:txBody")) {
// CTTextParagraphProperties defaultPr = null, lastPr = null;
// boolean hasLvl = false;
// for (CTTextParagraph p : txBody.getPArray()) {
// CTTextParagraphProperties pr = p.getPPr();
// if (pr.isSetLvl()) {
// hasLvl |= true;
// lastPr = pr;
// if (pr.getLvl() == level) return pr;
// } else {
// defaultPr = pr;
// }
// }
// if (!hasLvl) continue;
// if (level == 0 && defaultPr != null) return defaultPr;
// if (lastPr != null) return lastPr;
// break;
// }
//
// String err = "Failed to fetch default style for " + defaultStyleSelector + " and level=" + level;
// throw new IllegalArgumentException(err);
return null;
}
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
@ -860,9 +807,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
@Override
public double getDefaultFontSize() {
public Double getDefaultFontSize() {
CTTextCharacterProperties endPr = _p.getEndParaRPr();
return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100);
return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);
}
@Override
@ -871,6 +818,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
public BulletStyle getBulletStyle() {
if (!isBullet()) return null;
return new BulletStyle(){
public String getBulletCharacter() {
return XSLFTextParagraph.this.getBulletCharacter();
@ -880,7 +828,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
return XSLFTextParagraph.this.getBulletFont();
}
public double getBulletFontSize() {
public Double getBulletFontSize() {
return XSLFTextParagraph.this.getBulletFontSize();
}

View File

@ -17,26 +17,11 @@
package org.apache.poi.xslf.usermodel;
import java.awt.Color;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedString;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.Beta;
import org.apache.poi.xslf.model.CharacterPropertyFetcher;
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;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
/**
@ -89,28 +74,6 @@ public class XSLFTextRun implements TextRun {
return buf.toString();
}
/**
* Replace a tab with the effective number of white spaces.
*/
private String tab2space(){
AttributedString string = new AttributedString(" ");
// user can pass an object to convert fonts via a rendering hint
string.addAttribute(TextAttribute.FAMILY, getFontFamily());
string.addAttribute(TextAttribute.SIZE, (float)getFontSize());
TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
double wspace = l.getAdvance();
double tabSz = _p.getDefaultTabSize();
int numSpaces = (int)Math.ceil(tabSz / wspace);
StringBuffer buf = new StringBuffer();
for(int i = 0; i < numSpaces; i++) {
buf.append(' ');
}
return buf.toString();
}
public void setText(String text){
_r.setT(text);
}
@ -175,9 +138,10 @@ public class XSLFTextRun implements TextRun {
}
/**
* @return font size in points or -1 if font size is not set.
* @return font size in points or null if font size is not set.
*/
public double getFontSize(){
@Override
public Double getFontSize(){
double scale = 1;
CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit();
if(afit != null) scale = (double)afit.getFontScale() / 100000;
@ -192,7 +156,7 @@ public class XSLFTextRun implements TextRun {
}
};
fetchCharacterProperty(fetcher);
return fetcher.getValue() == null ? -1 : fetcher.getValue()*scale;
return fetcher.getValue() == null ? null : fetcher.getValue()*scale;
}
/**
@ -514,7 +478,7 @@ public class XSLFTextRun implements TextRun {
return new XSLFHyperlink(_r.getRPr().getHlinkClick(), this);
}
private boolean fetchCharacterProperty(CharacterPropertyFetcher fetcher){
private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){
boolean ok = false;
if(_r.isSetRPr()) ok = fetcher.fetch(getRPr());

View File

@ -125,7 +125,7 @@ public class TestXSLFAutoShape {
p.setIndent(2.0);
assertEquals(2.0, p.getIndent(), 0);
assertTrue(p.getXmlObject().getPPr().isSetIndent());
p.setIndent(-1);
p.setIndent(-1d);
assertEquals(0.0, p.getIndent(), 0);
assertFalse(p.getXmlObject().getPPr().isSetIndent());
p.setIndent(10.0);
@ -149,44 +149,44 @@ public class TestXSLFAutoShape {
assertFalse(p.getXmlObject().getPPr().isSetSpcAft());
p.setSpaceAfter(200);
p.setSpaceAfter(200d);
assertEquals(200000, p.getXmlObject().getPPr().getSpcAft().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPts());
p.setSpaceAfter(100);
p.setSpaceAfter(100d);
assertEquals(100000, p.getXmlObject().getPPr().getSpcAft().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPts());
p.setSpaceAfter(-20);
p.setSpaceAfter(-20d);
assertEquals(2000, p.getXmlObject().getPPr().getSpcAft().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPct());
p.setSpaceAfter(-10);
p.setSpaceAfter(-10d);
assertEquals(1000, p.getXmlObject().getPPr().getSpcAft().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPct());
assertFalse(p.getXmlObject().getPPr().isSetSpcBef());
p.setSpaceBefore(200);
p.setSpaceBefore(200d);
assertEquals(200000, p.getXmlObject().getPPr().getSpcBef().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPts());
p.setSpaceBefore(100);
p.setSpaceBefore(100d);
assertEquals(100000, p.getXmlObject().getPPr().getSpcBef().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPts());
p.setSpaceBefore(-20);
p.setSpaceBefore(-20d);
assertEquals(2000, p.getXmlObject().getPPr().getSpcBef().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPct());
p.setSpaceBefore(-10);
p.setSpaceBefore(-10d);
assertEquals(1000, p.getXmlObject().getPPr().getSpcBef().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPct());
assertFalse(p.getXmlObject().getPPr().isSetLnSpc());
p.setLineSpacing(200);
p.setLineSpacing(200d);
assertEquals(200000, p.getXmlObject().getPPr().getLnSpc().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPts());
p.setLineSpacing(100);
p.setLineSpacing(100d);
assertEquals(100000, p.getXmlObject().getPPr().getLnSpc().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPts());
p.setLineSpacing(-20);
p.setLineSpacing(-20d);
assertEquals(2000, p.getXmlObject().getPPr().getLnSpc().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPct());
p.setLineSpacing(-10);
p.setLineSpacing(-10d);
assertEquals(1000, p.getXmlObject().getPPr().getLnSpc().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPct());

View File

@ -92,7 +92,7 @@ public class TestXSLFTextParagraph {
assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0);
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0);
p.setLeftMargin(36); // 0.5"
p.setLeftMargin(36d); // 0.5"
leftMargin = p.getLeftMargin();
assertEquals(36.0, leftMargin, 0);
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;

View File

@ -21,12 +21,13 @@ package org.apache.poi.hslf.model.textproperties;
* Definition for the font alignment property.
*/
public class FontAlignmentProp extends TextProp {
public static final String NAME = "fontAlign";
public static final int BASELINE = 0;
public static final int TOP = 1;
public static final int CENTER = 2;
public static final int BOTTOM = 3;
public FontAlignmentProp() {
super(2, 0x10000, "fontAlign");
super(2, 0x10000, NAME);
}
}

View File

@ -31,47 +31,10 @@ import org.apache.poi.util.LittleEndian;
* properties, and the indent level if required.
*/
public class TextPropCollection {
/*
private static TextProp paragraphSpecialPropTypes[] = {
new ParagraphFlagsTextProp(),
new TextProp(2, 0x80, "bullet.char"),
new TextProp(2, 0x10, "bullet.font"),
new TextProp(2, 0x40, "bullet.size"),
new TextProp(4, 0x20, "bullet.color"),
new TextProp(2, 0xD00, "alignment"),
new TextProp(2, 0x1000, "linespacing"),
new TextProp(2, 0x2000, "spacebefore"),
new TextProp(2, 0x4000, "spaceafter"),
new TextProp(2, 0x8000, "text.offset"),
new TextProp(2, 0x10000, "bullet.offset"),
new TextProp(2, 0x20000, "defaulttab"),
new TextProp(2, 0x40000, "para_unknown_2"),
new TextProp(2, 0x80000, "para_unknown_3"),
new TextProp(2, 0x100000, "para_unknown_4"),
new TextProp(2, 0x200000, "para_unknown_5")
};
private static TextProp characterSpecialPropTypes[] = {
new CharFlagsTextProp(),
new TextProp(2, 0x10000, "font.index"),
new TextProp(2, 0x20000, "char_unknown_1"),
new TextProp(4, 0x40000, "char_unknown_2"),
new TextProp(2, 0x80000, "font.size"),
new TextProp(2, 0x100000, "char_unknown_3"),
new TextProp(4, 0x200000, "font.color"),
new TextProp(2, 0x800000, "char_unknown_4")
};
*/
/** All the different kinds of paragraph properties we might handle */
public static final TextProp[] paragraphTextPropTypes = {
// TextProp order is according to 2.9.20 TextPFException,
// bitmask order can be different
// new TextProp(0, 0x1, "hasBullet"),
// new TextProp(0, 0x2, "hasBulletFont"),
// new TextProp(0, 0x4, "hasBulletColor"),
// new TextProp(0, 0x8, "hasBulletSize"),
new ParagraphFlagsTextProp(),
new TextProp(2, 0x80, "bullet.char"),
new TextProp(2, 0x10, "bullet.font"),
@ -95,24 +58,9 @@ public class TextPropCollection {
new TextProp(0, 0x2000000, "hasBulletScheme"), // TODO: check size
// 0xFC000000 MUST be zero and MUST be ignored
};
/** All the different kinds of character properties we might handle */
public static final TextProp[] characterTextPropTypes = new TextProp[] {
// new TextProp(0, 0x1, "bold"),
// new TextProp(0, 0x2, "italic"),
// new TextProp(0, 0x4, "underline"),
// new TextProp(0, 0x8, "unused1"),
// new TextProp(0, 0x10, "shadow"),
// new TextProp(0, 0x20, "fehint"),
// new TextProp(0, 0x40, "unused2"),
// new TextProp(0, 0x80, "kumi"),
// new TextProp(0, 0x100, "strikethrough"),
// new TextProp(0, 0x200, "emboss"),
// new TextProp(0, 0x400, "nibble1"),
// new TextProp(0, 0x800, "nibble2"),
// new TextProp(0, 0x1000, "nibble3"),
// new TextProp(0, 0x2000, "nibble4"),
// new TextProp(0, 0x4000, "unused4"),
// new TextProp(0, 0x8000, "unused5"),
new TextProp(0, 0x100000, "pp10ext"),
new TextProp(0, 0x1000000, "newAsian.font.index"), // A bit that specifies whether the newEAFontRef field of the TextCFException10 structure that contains this CFMasks exists.
new TextProp(0, 0x2000000, "cs.font.index"), // A bit that specifies whether the csFontRef field of the TextCFException10 structure that contains this CFMasks exists.
@ -167,6 +115,19 @@ public class TextPropCollection {
return null;
}
public TextProp removeByName(String name) {
Iterator<TextProp> iter = textPropList.iterator();
TextProp tp = null;
while (iter.hasNext()) {
tp = iter.next();
if (tp.getName().equals(name)){
iter.remove();
break;
}
}
return tp;
}
/** Add the TextProp with this name to the list */
public TextProp addWithName(String name) {
// Find the base TextProp to base on
@ -192,6 +153,10 @@ public class TextPropCollection {
return textProp;
}
public TextPropType getTextPropType() {
return textPropType;
}
private TextProp[] getPotentialProperties() {
return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes;
}

View File

@ -17,6 +17,7 @@
package org.apache.poi.hslf.record;
import org.apache.poi.hslf.model.PPFont;
import org.apache.poi.util.POILogger;
import java.io.*;
@ -77,7 +78,7 @@ public final class FontCollection extends RecordContainer {
int idx = getFontIndex(name);
if (idx != -1) return idx;
return addFont(name, 0, 0, 4, 34);
return addFont(name, 0, 0, 4, PPFont.FF_SWISS | PPFont.VARIABLE_PITCH);
}
public int addFont(String name, int charset, int flags, int type, int pitch) {

View File

@ -76,16 +76,17 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
* This is the "workhorse" which returns the default style attrubutes.
*/
public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) {
if (_txmaster.length <= txtype) return null;
TxMasterStyleAtom t = _txmaster[txtype];
List<TextPropCollection> styles = isCharacter ? t.getCharacterStyles() : t.getParagraphStyles();
TextProp prop = null;
for (int i = level; i >= 0; i--) {
List<TextPropCollection> styles =
isCharacter ? _txmaster[txtype].getCharacterStyles() : _txmaster[txtype].getParagraphStyles();
if (i < styles.size()) prop = styles.get(i).findByName(name);
if (prop != null) break;
for (int i = Math.min(level, styles.size()-1); prop == null && i >= 0; i--) {
prop = styles.get(i).findByName(name);
}
if (prop == null) {
if(isCharacter) {
if (prop != null) return prop;
switch (txtype) {
case TextHeaderAtom.CENTRE_BODY_TYPE:
case TextHeaderAtom.HALF_BODY_TYPE:
@ -98,23 +99,8 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
default:
return null;
}
} else {
switch (txtype) {
case TextHeaderAtom.CENTRE_BODY_TYPE:
case TextHeaderAtom.HALF_BODY_TYPE:
case TextHeaderAtom.QUARTER_BODY_TYPE:
txtype = TextHeaderAtom.BODY_TYPE;
break;
case TextHeaderAtom.CENTER_TITLE_TYPE:
txtype = TextHeaderAtom.TITLE_TYPE;
break;
default:
return null;
}
}
prop = getStyleAttribute(txtype, level, name, isCharacter);
}
return prop;
return getStyleAttribute(txtype, level, name, isCharacter);
}
/**

View File

@ -49,7 +49,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
/* package */static final int AlignRight = 2;
/* package */static final int AlignJustify = 3;
// Note: These fields are protected to help with unit testing
// Other classes shouldn't really go playing with them!
private final TextHeaderAtom _headerAtom;
@ -58,7 +57,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
protected TextRulerAtom _ruler;
protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
protected HSLFTextShape _parentShape;
private HSLFSheet _sheet;
private int shapeId;
@ -178,7 +177,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
if (_headerAtom != null) _headerAtom.setTextType(runType);
}
/**
* Is this Text Run one from a {@link PPDrawing}, or is it
* one from the {@link SlideListWithText}?
@ -252,87 +250,63 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
return this.styleTextProp9Atom;
}
/**
* Fetch the value of the given Paragraph related TextProp.
* Returns -1 if that TextProp isn't present.
* If the TextProp isn't present, the value from the appropriate
* Master Sheet will apply.
*/
private int getParaTextPropVal(String propName) {
TextProp prop = _paragraphStyle.findByName(propName);
BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
if (prop == null && !hardAttribute){
HSLFSheet sheet = getSheet();
int txtype = getRunType();
HSLFMasterSheet master = sheet.getMasterSheet();
if (master != null)
prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, false);
}
return prop == null ? -1 : prop.getValue();
}
/**
* Sets the value of the given Character TextProp, add if required
* @param propName The name of the Character TextProp
* @param val The value to set for the TextProp
*/
public void setParaTextPropVal(String propName, int val) {
// Ensure we have the StyleTextProp atom we're going to need
assert(_paragraphStyle!=null);
TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);
tp.setValue(val);
}
@Override
public Iterator<HSLFTextRun> iterator() {
return _runs.iterator();
}
@Override
public double getLeftMargin() {
int val = getParaTextPropVal("text.offset");
return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
public Double getLeftMargin() {
TextProp val = getPropVal(_paragraphStyle, "text.offset", this);
return (val == null) ? null : Units.masterToPoints(val.getValue());
}
@Override
public void setLeftMargin(double leftMargin) {
int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
setParaTextPropVal("text.offset", val);
public void setLeftMargin(Double leftMargin) {
Integer val = (leftMargin == null) ? null : Units.pointsToMaster(leftMargin);
setPropVal(_paragraphStyle, "text.offset", val);
}
@Override
public double getRightMargin() {
public Double getRightMargin() {
// TODO: find out, how to determine this value
return 0;
return null;
}
@Override
public void setRightMargin(double rightMargin) {
public void setRightMargin(Double rightMargin) {
// TODO: find out, how to set this value
}
@Override
public double getIndent() {
int val = getParaTextPropVal("bullet.offset");
return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
public Double getIndent() {
TextProp val = getPropVal(_paragraphStyle, "bullet.offset", this);
return (val == null) ? null : Units.masterToPoints(val.getValue());
}
@Override
public void setIndent(double intent) {
int val = (int)(intent*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
setParaTextPropVal("bullet.offset", val);
public void setIndent(Double indent) {
Integer val = (indent == null) ? null : Units.pointsToMaster(indent);
setPropVal(_paragraphStyle, "bullet.offset", val);
}
@Override
public String getDefaultFontFamily() {
return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily());
String typeface = null;
if (!_runs.isEmpty()) {
typeface = _runs.get(0).getFontFamily();
}
return (typeface != null) ? typeface : "Arial";
}
@Override
public double getDefaultFontSize() {
return (_runs.isEmpty() ? 12 : _runs.get(0).getFontSize());
public Double getDefaultFontSize() {
Double d = null;
if (!_runs.isEmpty()) {
d = _runs.get(0).getFontSize();
}
return (d != null) ? d : 12d;
}
/**
@ -341,8 +315,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
* @param align - the type of alignment
*/
public void setAlignment(org.apache.poi.sl.usermodel.TextParagraph.TextAlign align) {
int alignInt;
switch (align) {
Integer alignInt = null;
if (align != null) switch (align) {
default:
case LEFT: alignInt = TextAlignmentProp.LEFT;break;
case CENTER: alignInt = TextAlignmentProp.CENTER; break;
@ -352,12 +326,14 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;
case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;
}
setParaTextPropVal("alignment", alignInt);
setPropVal(_paragraphStyle, "alignment", alignInt);
}
@Override
public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {
switch (getParaTextPropVal("alignment")) {
TextProp tp = getPropVal(_paragraphStyle, "alignment", this);
if (tp == null) return null;
switch (tp.getValue()) {
default:
case TextAlignmentProp.LEFT: return TextAlign.LEFT;
case TextAlignmentProp.CENTER: return TextAlign.CENTER;
@ -371,34 +347,33 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
@Override
public FontAlign getFontAlign() {
switch(getParaTextPropVal("fontAlign")) {
default:
case -1: return FontAlign.AUTO;
TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME, this);
if (tp == null) return null;
switch (tp.getValue()) {
case FontAlignmentProp.BASELINE: return FontAlign.BASELINE;
case FontAlignmentProp.TOP: return FontAlign.TOP;
case FontAlignmentProp.CENTER: return FontAlign.CENTER;
case FontAlignmentProp.BOTTOM: return FontAlign.BOTTOM;
default: return FontAlign.AUTO;
}
}
@Override
public BulletStyle getBulletStyle() {
if (getBulletChar() == 0) return null;
if (!isBullet()) return null;
return new BulletStyle() {
public String getBulletCharacter() {
char chr = HSLFTextParagraph.this.getBulletChar();
return (chr == 0 ? "" : ""+chr);
Character chr = HSLFTextParagraph.this.getBulletChar();
return (chr == null || chr == 0) ? "" : "" + chr;
}
public String getBulletFont() {
int fontIdx = HSLFTextParagraph.this.getBulletFont();
if (fontIdx == -1) return getDefaultFontFamily();
PPFont ppFont = getSheet().getSlideShow().getFont(fontIdx);
return ppFont.getFontName();
return HSLFTextParagraph.this.getBulletFont();
}
public double getBulletFontSize() {
public Double getBulletFontSize() {
return HSLFTextParagraph.this.getBulletSize();
}
@ -417,7 +392,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
_parentShape = parentShape;
}
/**
*
* @return indentation level
@ -449,66 +423,62 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
}
/**
* Returns whether this rich text run has bullets
*/
public boolean isBulletHard() {
return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
}
/**
* Sets the bullet character
*/
public void setBulletChar(char c) {
setParaTextPropVal("bullet.char", c);
public void setBulletChar(Character c) {
Integer val = (c == null) ? null : (int)c.charValue();
setPropVal(_paragraphStyle, "bullet.char", val);
}
/**
* Returns the bullet character
*/
public char getBulletChar() {
int val = getParaTextPropVal("bullet.char");
return (char)(val == -1 ? 0 : val);
public Character getBulletChar() {
TextProp tp = getPropVal(_paragraphStyle, "bullet.char", this);
return (tp == null) ? null : (char)tp.getValue();
}
/**
* Sets the bullet size
*/
public void setBulletSize(int size) {
setParaTextPropVal("bullet.size", size);
public void setBulletSize(Double size) {
setPctOrPoints("bullet.size", size);
}
/**
* Returns the bullet size
* Returns the bullet size, null if unset
*/
public int getBulletSize() {
return getParaTextPropVal("bullet.size");
public Double getBulletSize() {
return getPctOrPoints("bullet.size");
}
/**
* Sets the bullet color
*/
public void setBulletColor(Color color) {
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
setParaTextPropVal("bullet.color", rgb);
Integer val = (color == null) ? null : new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
setPropVal(_paragraphStyle, "bullet.color", val);
}
/**
* Returns the bullet color
*/
public Color getBulletColor() {
int rgb = getParaTextPropVal("bullet.color");
if (rgb == -1) {
TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this);
if (tp == null) {
// if bullet color is undefined, return color of first run
if (_runs.isEmpty()) return null;
return _runs.get(0).getFontColor();
return (_runs.isEmpty()) ? null : _runs.get(0).getFontColor();
}
int rgb = tp.getValue();
int cidx = rgb >> 24;
if (rgb % 0x1000000 == 0) {
if (_sheet == null) return null;
if (_sheet == null)
return null;
ColorSchemeAtom ca = _sheet.getColorScheme();
if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
if (cidx >= 0 && cidx <= 7)
rgb = ca.getColor(cidx);
}
Color tmp = new Color(rgb, true);
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
@ -517,124 +487,133 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
/**
* Sets the bullet font
*/
public void setBulletFont(int idx) {
setParaTextPropVal("bullet.font", idx);
public void setBulletFont(String typeface) {
if (typeface == null) {
setPropVal(_paragraphStyle, "bullet.font", null);
setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false);
}
FontCollection fc = getSheet().getSlideShow().getFontCollection();
int idx = fc.addFont(typeface);
setPropVal(_paragraphStyle, "bullet.font", idx);
setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
}
/**
* Returns the bullet font
*/
public int getBulletFont() {
return getParaTextPropVal("bullet.font");
public String getBulletFont() {
TextProp tp = getPropVal(_paragraphStyle, "bullet.font", this);
if (tp == null) return getDefaultFontFamily();
PPFont ppFont = getSheet().getSlideShow().getFont(tp.getValue());
assert(ppFont != null);
return ppFont.getFontName();
}
@Override
public void setLineSpacing(double lineSpacing) {
// if lineSpacing < 0, we need to convert points (common interface) to master units (hslf)
if (lineSpacing < 0) {
lineSpacing = (lineSpacing*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
}
setParaTextPropVal("linespacing", (int)lineSpacing);
public void setLineSpacing(Double lineSpacing) {
setPctOrPoints("linespacing", lineSpacing);
}
@Override
public double getLineSpacing() {
double val = getParaTextPropVal("linespacing");
// if lineSpacing < 0, we need to convert master units (hslf) to points (common interface)
if (val == -1) return 0;
if (val < -1) val *= HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
return val;
public Double getLineSpacing() {
return getPctOrPoints("linespacing");
}
/**
* Sets spacing before a paragraph.
* <p>
* If spacebefore >= 0, then spacebefore is a percentage of normal line height.
* If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
* </p>
*/
public void setSpaceBefore(int val) {
setParaTextPropVal("spacebefore", val);
}
/**
* Returns spacing before a paragraph
* <p>
* If spacebefore >= 0, then spacebefore is a percentage of normal line height.
* If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
* </p>
*
* @return the spacing before a paragraph
*/
@Override
public double getSpaceBefore() {
int val = getParaTextPropVal("spacebefore");
return val == -1 ? 0 : val;
public void setSpaceBefore(Double spaceBefore) {
setPctOrPoints("spacebefore", spaceBefore);
}
/**
* Sets spacing after a paragraph.
* <p>
* If spaceafter >= 0, then spaceafter is a percentage of normal line height.
* If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
* </p>
*/
public void setSpaceAfter(int val) {
setParaTextPropVal("spaceafter", val);
}
/**
* Returns spacing after a paragraph
* <p>
* If spaceafter >= 0, then spaceafter is a percentage of normal line height.
* If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
* </p>
*
* @return the spacing before a paragraph
*/
@Override
public double getSpaceAfter() {
int val = getParaTextPropVal("spaceafter");
return val == -1 ? 0 : val;
public Double getSpaceBefore() {
return getPctOrPoints("spacebefore");
}
@Override
public void setSpaceAfter(Double spaceAfter) {
setPctOrPoints("spaceafter", spaceAfter);
}
@Override
public Double getSpaceAfter() {
return getPctOrPoints("spaceafter");
}
@Override
public Double getDefaultTabSize() {
// TODO: implement
return null;
}
private Double getPctOrPoints(String propName) {
TextProp tp = getPropVal(_paragraphStyle, propName, this);
if (tp == null) return null;
int val = tp.getValue();
return (val < 0) ? Units.masterToPoints(val) : val;
}
private void setPctOrPoints(String propName, Double dval) {
Integer ival = null;
if (dval != null) {
ival = (dval < 0) ? Units.pointsToMaster(dval) : dval.intValue();
}
setPropVal(_paragraphStyle, propName, ival);
}
private boolean getFlag(int index) {
BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME, this);
return (tp == null) ? false : tp.getSubValue(index);
}
private void setFlag(int index, boolean value) {
BitMaskTextProp tp = (BitMaskTextProp)_paragraphStyle.addWithName(ParagraphFlagsTextProp.NAME);
tp.setSubValue(value, index);
}
/**
* Returns the named TextProp, either by fetching it (if it exists) or adding it
* (if it didn't)
* @param textPropCol The TextPropCollection to fetch from / add into
* @param textPropName The name of the TextProp to fetch/add
* Fetch the value of the given Paragraph related TextProp. Returns null if
* that TextProp isn't present. If the TextProp isn't present, the value
* from the appropriate Master Sheet will apply.
*/
protected static TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) {
// Fetch / Add the TextProp
return textPropCol.addWithName(textPropName);
}
protected static TextProp getPropVal(TextPropCollection props, String propName, HSLFTextParagraph paragraph) {
TextProp prop = props.findByName(propName);
if (prop != null) return prop;
protected boolean getFlag(int index) {
if (_paragraphStyle == null) return false;
BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);
boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
if (hardAttribute) return null;
BitMaskTextProp prop = (BitMaskTextProp) _paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
if (prop == null) {
if (_sheet != null) {
int txtype = getRunType();
HSLFMasterSheet master = _sheet.getMasterSheet();
if (master != null) {
prop = (BitMaskTextProp) master.getStyleAttribute(txtype, getIndentLevel(), ParagraphFlagsTextProp.NAME, false);
}
} else {
HSLFSheet sheet = paragraph.getSheet();
int txtype = paragraph.getRunType();
HSLFMasterSheet master = sheet.getMasterSheet();
if (master == null) {
logger.log(POILogger.WARN, "MasterSheet is not available");
}
return null;
}
return prop == null ? false : prop.getSubValue(index);
boolean isChar = props.getTextPropType() == TextPropType.character;
return master.getStyleAttribute(txtype, paragraph.getIndentLevel(), propName, isChar);
}
protected void setFlag(int index, boolean value) {
// Ensure we have the StyleTextProp atom we're going to need
assert(_paragraphStyle!=null);
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);
prop.setSubValue(value,index);
/**
* Returns the named TextProp, either by fetching it (if it exists) or
* adding it (if it didn't)
*
* @param props the TextPropCollection to fetch from / add into
* @param name the name of the TextProp to fetch/add
* @param val the value, null if unset
*/
protected static void setPropVal(TextPropCollection props, String name, Integer val) {
if (val == null) {
props.removeByName(name);
return;
}
// Fetch / Add the TextProp
TextProp tp = props.addWithName(name);
tp.setValue(val);
}
/**
@ -691,7 +670,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
return style;
}
/**
* Saves the modified paragraphs/textrun to the records.
* Also updates the styles to the correct text length.

View File

@ -17,7 +17,8 @@
package org.apache.poi.hslf.usermodel;
import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.fetchOrAddTextProp;
import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.setPropVal;
import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getPropVal;
import java.awt.Color;
@ -132,39 +133,17 @@ public final class HSLFTextRun implements TextRun {
* it if required.
*/
private void setCharFlagsTextPropVal(int index, boolean value) {
// TODO: check if paragraph/chars can be handled the same ...
if (getFlag(index) != value) setFlag(index, value);
}
/**
* Fetch the value of the given Character related TextProp.
* Returns -1 if that TextProp isn't present.
* If the TextProp isn't present, the value from the appropriate
* Master Sheet will apply.
*/
private int getCharTextPropVal(String propName) {
TextProp prop = null;
if (characterStyle != null){
prop = characterStyle.findByName(propName);
}
if (prop == null){
HSLFSheet sheet = parentParagraph.getSheet();
int txtype = parentParagraph.getRunType();
HSLFMasterSheet master = sheet.getMasterSheet();
if (master != null)
prop = master.getStyleAttribute(txtype, parentParagraph.getIndentLevel(), propName, true);
}
return prop == null ? -1 : prop.getValue();
}
/**
* Sets the value of the given Paragraph TextProp, add if required
* @param propName The name of the Paragraph TextProp
* @param val The value to set for the TextProp
*/
public void setCharTextPropVal(String propName, int val) {
TextProp tp = fetchOrAddTextProp(characterStyle, propName);
tp.setValue(val);
setPropVal(characterStyle, propName, val);
}
@ -260,8 +239,8 @@ public final class HSLFTextRun implements TextRun {
* @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
*/
public int getSuperscript() {
int val = getCharTextPropVal("superscript");
return val == -1 ? 0 : val;
TextProp tp = getPropVal(characterStyle, "superscript", parentParagraph);
return tp == null ? 0 : tp.getValue();
}
/**
@ -270,14 +249,15 @@ public final class HSLFTextRun implements TextRun {
* @param val the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
*/
public void setSuperscript(int val) {
setCharTextPropVal("superscript", val);
setPropVal(characterStyle, "superscript", val);
}
/**
* Gets the font size
*/
public double getFontSize() {
return getCharTextPropVal("font.size");
public Double getFontSize() {
TextProp tp = getPropVal(characterStyle, "font.size", parentParagraph);
return tp == null ? null : (double)tp.getValue();
}
@ -292,7 +272,8 @@ public final class HSLFTextRun implements TextRun {
* Gets the font index
*/
public int getFontIndex() {
return getCharTextPropVal("font.index");
TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph);
return tp == null ? -1 : tp.getValue();
}
/**
@ -329,9 +310,9 @@ public final class HSLFTextRun implements TextRun {
if (sheet == null || slideShow == null) {
return _fontFamily;
}
int fontIdx = getCharTextPropVal("font.index");
if(fontIdx == -1) { return null; }
return slideShow.getFontCollection().getFontWithId(fontIdx);
TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph);
if (tp == null) { return null; }
return slideShow.getFontCollection().getFontWithId(tp.getValue());
}
/**
@ -339,7 +320,9 @@ public final class HSLFTextRun implements TextRun {
* @see java.awt.Color
*/
public Color getFontColor() {
int rgb = getCharTextPropVal("font.color");
TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph);
if (tp == null) return null;
int rgb = tp.getValue();
int cidx = rgb >> 24;
if (rgb % 0x1000000 == 0){
@ -370,7 +353,7 @@ public final class HSLFTextRun implements TextRun {
}
protected void setFlag(int index, boolean value) {
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME);
BitMaskTextProp prop = (BitMaskTextProp)characterStyle.addWithName(CharFlagsTextProp.NAME);
prop.setSubValue(value, index);
}

View File

@ -55,12 +55,21 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
double rightInset = insets.right;
double penY = y;
double leftMargin = paragraph.getLeftMargin();
boolean firstLine = true;
double indent = paragraph.getIndent();
Double leftMargin = paragraph.getLeftMargin();
Double indent = paragraph.getIndent();
if (leftMargin == null) {
leftMargin = (indent != null) ? -indent : 0;
}
if (indent == null) {
indent = (leftMargin != null) ? -leftMargin : 0;
}
//The vertical line spacing
double spacing = paragraph.getLineSpacing();
Double spacing = paragraph.getLineSpacing();
if (spacing == null) spacing = 100d;
for(DrawTextFragment line : lines){
double penX = x + leftMargin;
@ -77,7 +86,7 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
bullet.setPosition(penX + indent, penY);
} else if(indent > 0){
// a positive value means the "First Line" indentation:
// the first line is indented and other lines start at the bullet ofset
// the first line is indented and other lines start at the bullet offset
bullet.setPosition(penX, penY);
penX += indent;
} else {
@ -96,7 +105,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
switch (paragraph.getTextAlign()) {
TextAlign ta = paragraph.getTextAlign();
if (ta == null) ta = TextAlign.LEFT;
switch (ta) {
case CENTER:
penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2;
break;
@ -219,9 +230,10 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
if (buColor == null) buColor = (Color)firstLineAttr.getAttribute(TextAttribute.FOREGROUND);
float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
float buSz = (float)bulletStyle.getBulletFontSize();
Double buSz = bulletStyle.getBulletFontSize();
if (buSz == null) buSz = 100d;
if (buSz > 0) fontSize *= buSz* 0.01;
else fontSize = -buSz;
else fontSize = (float)-buSz;
AttributedString str = new AttributedString(buCharacter);
@ -237,10 +249,13 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
protected String getRenderableText(TextRun tr) {
StringBuilder buf = new StringBuilder();
TextCap cap = tr.getTextCap();
String tabs = null;
for (char c : tr.getRawText().toCharArray()) {
if(c == '\t') {
// TODO: finish support for tabs
buf.append(" ");
if (tabs == null) {
tabs = tab2space(tr);
}
buf.append(tabs);
continue;
}
@ -256,6 +271,34 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
return buf.toString();
}
/**
* Replace a tab with the effective number of white spaces.
*/
private String tab2space(TextRun tr) {
AttributedString string = new AttributedString(" ");
String typeFace = tr.getFontFamily();
if (typeFace == null) typeFace = "Lucida Sans";
string.addAttribute(TextAttribute.FAMILY, typeFace);
Double fs = tr.getFontSize();
if (fs == null) fs = 12d;
string.addAttribute(TextAttribute.SIZE, fs.floatValue());
TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
double wspace = l.getAdvance();
Double tabSz = paragraph.getDefaultTabSize();
if (tabSz == null) tabSz = wspace*4;
int numSpaces = (int)Math.ceil(tabSz / wspace);
StringBuilder buf = new StringBuilder();
for(int i = 0; i < numSpaces; i++) {
buf.append(' ');
}
return buf.toString();
}
/**
* Returns wrapping width to break lines in this paragraph
*
@ -271,8 +314,14 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
double leftMargin = paragraph.getLeftMargin();
double indent = paragraph.getIndent();
Double leftMargin = paragraph.getLeftMargin();
Double indent = paragraph.getIndent();
if (leftMargin == null) {
leftMargin = (indent != null) ? -indent : 0;
}
if (indent == null) {
indent = (leftMargin != null) ? -leftMargin : 0;
}
double width;
TextShape<? extends TextParagraph<T>> ts = paragraph.getParentShape();
@ -323,7 +372,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
text.append(runText);
int endIndex = text.length();
attList.add(new AttributedStringData(TextAttribute.FOREGROUND, run.getFontColor(), beginIndex, endIndex));
Color fgColor = run.getFontColor();
if (fgColor == null) fgColor = Color.BLACK;
attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgColor, beginIndex, endIndex));
// user can pass an custom object to convert fonts
String fontFamily = run.getFontFamily();
@ -335,10 +386,14 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
if(fontHandler != null) {
fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());
}
if (fontFamily == null) {
fontFamily = paragraph.getDefaultFontFamily();
}
attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFamily, beginIndex, endIndex));
float fontSz = (float)run.getFontSize();
attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, beginIndex, endIndex));
Double fontSz = run.getFontSize();
if (fontSz == null) fontSz = paragraph.getDefaultFontSize();
attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), beginIndex, endIndex));
if(run.isBold()) {
attList.add(new AttributedStringData(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, beginIndex, endIndex));
@ -364,9 +419,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
// ensure that the paragraph contains at least one character
// We need this trick to correctly measure text
if (text.length() == 0) {
float fontSz = (float)paragraph.getDefaultFontSize();
Double fontSz = paragraph.getDefaultFontSize();
text.append(" ");
attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, 0, 1));
attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), 0, 1));
}
AttributedString string = new AttributedString(text.toString());

View File

@ -95,7 +95,8 @@ public class DrawTextShape<T extends TextShape<? extends TextParagraph<? extends
if (!isFirstLine) {
// the amount of vertical white space before the paragraph
double spaceBefore = p.getSpaceBefore();
Double spaceBefore = p.getSpaceBefore();
if (spaceBefore == null) spaceBefore = 0d;
if(spaceBefore > 0) {
// positive value means percentage spacing of the height of the first line, e.g.
// the higher the first line, the bigger the space before the paragraph
@ -112,7 +113,8 @@ public class DrawTextShape<T extends TextShape<? extends TextParagraph<? extends
y += dp.getY();
if (paragraphs.hasNext()) {
double spaceAfter = p.getSpaceAfter();
Double spaceAfter = p.getSpaceAfter();
if (spaceAfter == null) spaceAfter = 0d;
if(spaceAfter > 0) {
// positive value means percentage spacing of the height of the last line, e.g.
// the higher the last line, the bigger the space after the paragraph

View File

@ -104,7 +104,15 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
public interface BulletStyle {
String getBulletCharacter();
String getBulletFont();
double getBulletFontSize();
/**
* The bullet point font size
* If bulletFontSize >= 0, then space is a percentage of normal line height.
* If bulletFontSize < 0, the absolute value in points
*
* @return the bullet point font size
*/
Double getBulletFontSize();
Color getBulletFontColor();
}
@ -116,9 +124,30 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
* If spaceBefore < 0, the absolute value in points
* </p>
*
* @return the vertical white space before the paragraph
* @return the vertical white space before the paragraph, or null if unset
*/
double getSpaceBefore();
Double getSpaceBefore();
/**
* Set the amount of vertical white space that will be present before the paragraph.
* This space is specified in either percentage or points:
* <p>
* If spaceBefore >= 0, then space is a percentage of normal line height.
* If spaceBefore < 0, the absolute value of linespacing is the spacing in points
* </p>
* Examples:
* <pre><code>
* // The paragraph will be formatted to have a spacing before the paragraph text.
* // The spacing will be 200% of the size of the largest text on each line
* paragraph.setSpaceBefore(200);
*
* // The spacing will be a size of 48 points
* paragraph.setSpaceBefore(-48.0);
* </code></pre>
*
* @param spaceBefore the vertical white space before the paragraph, null to unset
*/
void setSpaceBefore(Double spaceBefore);
/**
* The amount of vertical white space after the paragraph
@ -128,40 +157,74 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
* If spaceBefore < 0, the absolute value of linespacing is the spacing in points
* </p>
*
* @return the vertical white space after the paragraph
* @return the vertical white space after the paragraph or null, if unset
*/
double getSpaceAfter();
Double getSpaceAfter();
/**
* @return the left margin (in points) of the paragraph
* Set the amount of vertical white space that will be present after the paragraph.
* This space is specified in either percentage or points:
* <p>
* If spaceAfter >= 0, then space is a percentage of normal line height.
* If spaceAfter < 0, the absolute value of linespacing is the spacing in points
* </p>
* Examples:
* <pre><code>
* // The paragraph will be formatted to have a spacing after the paragraph text.
* // The spacing will be 200% of the size of the largest text on each line
* paragraph.setSpaceAfter(200);
*
* // The spacing will be a size of 48 points
* paragraph.setSpaceAfter(-48.0);
* </code></pre>
*
* @param spaceAfter the vertical white space after the paragraph, null to unset
*/
double getLeftMargin();
public void setSpaceAfter(Double spaceAfter);
/**
* @param leftMargin the left margin (in points)
* @return the left margin (in points) of the paragraph or null, if unset
*/
void setLeftMargin(double leftMargin);
Double getLeftMargin();
/**
* Specifies the left margin of the paragraph. This is specified in addition to the text body
* inset and applies only to this text paragraph. That is the text body Inset and the LeftMargin
* attributes are additive with respect to the text position.
*
* @param leftMargin the left margin (in points) or null to unset
*/
void setLeftMargin(Double leftMargin);
/**
* @return the right margin (in points) of the paragraph
* Specifies the right margin of the paragraph. This is specified in addition to the text body
* inset and applies only to this text paragraph. That is the text body Inset and the RightMargin
* attributes are additive with respect to the text position.
*
* The right margin is not support and therefore ignored by the HSLF implementation.
*
* @return the right margin (in points) of the paragraph or null, if unset
*/
double getRightMargin();
Double getRightMargin();
/**
* @param rightMargin the right margin (in points) of the paragraph
*/
void setRightMargin(double rightMargin);
void setRightMargin(Double rightMargin);
/**
* @return the indent (in points) applied to the first line of text in the paragraph.
* or null, if unset
*/
double getIndent();
Double getIndent();
/**
* Specifies the indent size that will be applied to the first line of text in the paragraph.
*
* @param indent the indent (in points) applied to the first line of text in the paragraph
*/
void setIndent(double indent);
void setIndent(Double indent);
/**
* Returns the vertical line spacing that is to be used within a paragraph.
@ -171,9 +234,9 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
* If linespacing < 0, the absolute value of linespacing is the spacing in points
* </p>
*
* @return the vertical line spacing.
* @return the vertical line spacing or null, if unset
*/
double getLineSpacing();
Double getLineSpacing();
/**
* This element specifies the vertical line spacing that is to be used within a paragraph.
@ -196,14 +259,14 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
*
* @param linespacing the vertical line spacing
*/
void setLineSpacing(double lineSpacing);
void setLineSpacing(Double lineSpacing);
String getDefaultFontFamily();
/**
* @return the default font size, in case its not set in the textrun
* @return the default font size, in case its not set in the textrun or null, if unset
*/
double getDefaultFontSize();
Double getDefaultFontSize();
/**
* Returns the alignment that is applied to the paragraph.
@ -217,8 +280,10 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
/**
* Returns the font alignment that is applied to the paragraph.
*
* If this attribute is omitted, then a value of auto (~ left) is implied.
* @return ??? alignment that is applied to the paragraph
* If this attribute is omitted, then null is return,
* user code can imply the a value of {@link FontAlign#AUTO}
*
* @return alignment that is applied to the paragraph
*/
FontAlign getFontAlign();
@ -227,5 +292,11 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
*/
BulletStyle getBulletStyle();
/**
* @return the default size for a tab character within this paragraph in points, null if unset
*/
Double getDefaultTabSize();
TextShape<? extends TextParagraph<T>> getParentShape();
}

View File

@ -21,8 +21,6 @@ import java.awt.Color;
/**
* Some text.
*
* TODO - decide on how we do rich text stuff
*/
public interface TextRun {
enum TextCap {
@ -31,13 +29,13 @@ public interface TextRun {
ALL
}
public String getRawText();
public void setText(String text);
String getRawText();
void setText(String text);
TextCap getTextCap();
Color getFontColor();
double getFontSize();
Double getFontSize();
String getFontFamily();
boolean isBold();

View File

@ -22,8 +22,7 @@ import static org.junit.Assert.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import javax.imageio.ImageIO;
@ -35,7 +34,6 @@ import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.util.JvmBugs;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.junit.Ignore;
import org.junit.Test;
/**
@ -142,29 +140,43 @@ public final class TestPicture {
@Test
// @Ignore("Just for visual validation - antialiasing is different on various systems")
public void bug54541() throws Exception {
String file = new String[]{
"54542_cropped_bitmap.pptx",
"54541_cropped_bitmap.ppt",
"54541_cropped_bitmap2.ppt",
"sample_pptx_grouping_issues.pptx"
}[3];
String files[] = {
// "sample_pptx_grouping_issues.pptx",
// "54542_cropped_bitmap.pptx",
// "54541_cropped_bitmap.ppt",
// "54541_cropped_bitmap2.ppt",
// "alterman_security.ppt",
"alterman_security2.pptx",
};
BitSet pages = new BitSet();
pages.set(2);
for (String file : files) {
InputStream is = _slTests.openResourceAsStream(file);
SlideShow ss = file.endsWith("pptx") ? new XMLSlideShow(is) : new HSLFSlideShow(is);
is.close();
boolean debugOut = false;
Dimension pg = ss.getPageSize();
int i=1;
for (Slide<?,?,?> slide : ss.getSlides()) {
int slideNo = slide.getSlideNumber();
if (!pages.get(slideNo-1)) {
if (pages.nextSetBit(slideNo-1) == -1) break; else continue;
}
if (debugOut) {
DummyGraphics2d graphics = new DummyGraphics2d();
slide.draw(graphics);
} else {
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB);
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
fixFonts(graphics);
slide.draw(graphics);
ImageIO.write(img, "PNG", new File("test"+(i++)+"hslf.png"));
graphics.setColor(Color.BLACK);
graphics.setStroke(new BasicStroke(1));
graphics.drawRect(0, 0, (int)pg.getWidth()-1, (int)pg.getHeight()-1);
ImageIO.write(img, "PNG", new File(file.replaceFirst(".pptx?", "-")+slideNo+".png"));
}
}
}
}

View File

@ -470,7 +470,7 @@ public final class TestRichTextRun {
assertEquals(expected, HSLFTextParagraph.getRawText(txt.get(1)));
assertEquals(4, txt.get(1).size());
rt = txt.get(1).get(0);
assertEquals('\u2022', rt.getBulletChar());
assertEquals('\u2022', (char)rt.getBulletChar());
assertTrue(rt.isBullet());
@ -486,7 +486,7 @@ public final class TestRichTextRun {
assertEquals(4, txt.get(0).size());
rt = txt.get(0).get(0);
assertTrue(rt.isBullet());
assertEquals('\u2022', rt.getBulletChar());
assertEquals('\u2022', (char)rt.getBulletChar());
expected =
"I\u2019m a text box with user-defined\r" +
@ -495,7 +495,7 @@ public final class TestRichTextRun {
assertEquals(2, txt.get(1).size());
rt = txt.get(1).get(0);
assertTrue(rt.isBullet());
assertEquals('\u263A', rt.getBulletChar());
assertEquals('\u263A', (char)rt.getBulletChar());
}
@Test
@ -513,8 +513,8 @@ public final class TestRichTextRun {
HSLFTextRun tr = rt.getTextRuns().get(0);
tr.setFontSize(42);
rt.setBullet(true);
rt.setLeftMargin(50);
rt.setIndent(0);
rt.setLeftMargin(50d);
rt.setIndent(0d);
rt.setBulletChar('\u263A');
slide.addShape(shape);
@ -522,7 +522,7 @@ public final class TestRichTextRun {
assertEquals(true, rt.isBullet());
assertEquals(50.0, rt.getLeftMargin(), 0);
assertEquals(0, rt.getIndent(), 0);
assertEquals('\u263A', rt.getBulletChar());
assertEquals('\u263A', (char)rt.getBulletChar());
shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300));
slide.addShape(shape);
@ -541,7 +541,7 @@ public final class TestRichTextRun {
assertEquals(true, rt.isBullet());
assertEquals(50.0, rt.getLeftMargin(), 0);
assertEquals(0, rt.getIndent(), 0);
assertEquals('\u263A', rt.getBulletChar());
assertEquals('\u263A', (char)rt.getBulletChar());
}
@Test

View File

@ -556,7 +556,7 @@ public final class TestTextRun {
int i=0;
for (List<HSLFTextParagraph> textParas : slide.getTextParagraphs()) {
assertEquals("Arial", textParas.get(0).getTextRuns().get(0).getFontFamily());
assertEquals(sizes[i++], (int)textParas.get(0).getTextRuns().get(0).getFontSize());
assertEquals(sizes[i++], textParas.get(0).getTextRuns().get(0).getFontSize().intValue());
}
}

Binary file not shown.