git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1686117 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_13_FINAL
@@ -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" + |
@@ -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( |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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,53 +651,70 @@ 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()){ | |||
case STPlaceholderType.INT_TITLE: | |||
case STPlaceholderType.INT_CTR_TITLE: | |||
defaultStyleSelector = "titleStyle"; | |||
break; | |||
case STPlaceholderType.INT_FTR: | |||
case STPlaceholderType.INT_SLD_NUM: | |||
case STPlaceholderType.INT_DT: | |||
defaultStyleSelector = "otherStyle"; | |||
break; | |||
default: | |||
defaultStyleSelector = "bodyStyle"; | |||
break; | |||
} | |||
String defaultStyleSelector; | |||
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: | |||
defaultStyleSelector = "otherStyle"; | |||
break; | |||
default: | |||
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( | |||
"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"); | |||
if (o.length == 1){ | |||
String nsDecl = | |||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " + | |||
"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(); | |||
} | |||
@@ -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()); |
@@ -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()); | |||
@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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. | |||
@@ -166,6 +114,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) { | |||
@@ -192,6 +153,10 @@ public class TextPropCollection { | |||
return textProp; | |||
} | |||
public TextPropType getTextPropType() { | |||
return textPropType; | |||
} | |||
private TextProp[] getPotentialProperties() { | |||
return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes; | |||
} |
@@ -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.*; | |||
@@ -75,9 +76,9 @@ public final class FontCollection extends RecordContainer { | |||
*/ | |||
public int addFont(String name) { | |||
int idx = getFontIndex(name); | |||
if(idx != -1) return idx; | |||
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) { |
@@ -76,45 +76,31 @@ 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) { | |||
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; | |||
} | |||
} 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); | |||
if (prop != null) return prop; | |||
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; | |||
} | |||
return prop; | |||
return getStyleAttribute(txtype, level, name, isCharacter); | |||
} | |||
/** |
@@ -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) { | |||
if(getFlag(index) != value) setFlag(index, 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); | |||
} | |||
@@ -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(); | |||
if(buSz > 0) fontSize *= buSz* 0.01; | |||
else fontSize = -buSz; | |||
Double buSz = bulletStyle.getBulletFontSize(); | |||
if (buSz == null) buSz = 100d; | |||
if (buSz > 0) fontSize *= buSz* 0.01; | |||
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; | |||
} | |||
@@ -255,6 +270,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()); |
@@ -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 |
@@ -104,10 +104,18 @@ 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(); | |||
} | |||
/** | |||
* The amount of vertical white space before the paragraph | |||
* This may be specified in two different ways, percentage spacing and font point spacing: | |||
@@ -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); | |||
/** | |||
* @return the left margin (in points) of the paragraph or null, if unset | |||
*/ | |||
Double getLeftMargin(); | |||
/** | |||
* @param leftMargin the left margin (in points) | |||
* 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); | |||
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(); | |||
} |
@@ -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(); |
@@ -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]; | |||
InputStream is = _slTests.openResourceAsStream(file); | |||
SlideShow ss = file.endsWith("pptx") ? new XMLSlideShow(is) : new HSLFSlideShow(is); | |||
is.close(); | |||
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); | |||
boolean debugOut = false; | |||
Dimension pg = ss.getPageSize(); | |||
int i=1; | |||
for(Slide<?,?,?> slide : ss.getSlides()) { | |||
if (debugOut) { | |||
DummyGraphics2d graphics = new DummyGraphics2d(); | |||
slide.draw(graphics); | |||
} else { | |||
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB); | |||
Graphics2D graphics = img.createGraphics(); | |||
fixFonts(graphics); | |||
slide.draw(graphics); | |||
ImageIO.write(img, "PNG", new File("test"+(i++)+"hslf.png")); | |||
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(); | |||
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_ARGB); | |||
Graphics2D graphics = img.createGraphics(); | |||
fixFonts(graphics); | |||
slide.draw(graphics); | |||
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")); | |||
} | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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()); | |||
} | |||
} | |||