#61169 - Text with Japanese characters overflows textbox

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1798986 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2017-06-17 00:00:49 +00:00
parent b1ed57750d
commit 0e57435abe
5 changed files with 101 additions and 38 deletions

View File

@ -69,11 +69,20 @@ public class DrawTextFragment implements Drawable {
/** /**
* @return full height of this text run which is sum of ascent, descent and leading * @return full height of this text run which is sum of ascent, descent and leading
*/ */
public float getHeight(){ public float getHeight(){
double h = Math.ceil(layout.getAscent()) + Math.ceil(layout.getDescent()) + layout.getLeading(); double h = Math.ceil(layout.getAscent()) + Math.ceil(layout.getDescent()) + getLeading();
return (float)h; return (float)h;
} }
/**
* @return the leading height before/after a text line
*/
public float getLeading() {
// fix invalid leadings (leading == 0) by fallback to descent
double l = layout.getLeading();
return (float)(l == 0 ? layout.getDescent() : l);
}
/** /**
* *
* @return width if this text run * @return width if this text run

View File

@ -215,6 +215,10 @@ public class DrawTextParagraph implements Drawable {
y = penY - y; y = penY - y;
} }
public float getFirstLineLeading() {
return (lines.isEmpty()) ? 0 : lines.get(0).getLeading();
}
public float getFirstLineHeight() { public float getFirstLineHeight() {
return (lines.isEmpty()) ? 0 : lines.get(0).getHeight(); return (lines.isEmpty()) ? 0 : lines.get(0).getHeight();
} }
@ -253,7 +257,8 @@ public class DrawTextParagraph implements Drawable {
for (;;) { for (;;) {
int startIndex = measurer.getPosition(); int startIndex = measurer.getPosition();
double wrappingWidth = getWrappingWidth(lines.size() == 0, graphics) + 1; // add a pixel to compensate rounding errors // add a pixel to compensate rounding errors
double wrappingWidth = getWrappingWidth(lines.isEmpty(), graphics) + 1;
// shape width can be smaller that the sum of insets (this was proved by a test file) // shape width can be smaller that the sum of insets (this was proved by a test file)
if(wrappingWidth < 0) { if(wrappingWidth < 0) {
wrappingWidth = 1; wrappingWidth = 1;

View File

@ -137,10 +137,7 @@ public class DrawTextShape extends DrawSimpleShape {
DrawFactory fact = DrawFactory.getInstance(graphics); DrawFactory fact = DrawFactory.getInstance(graphics);
double y0 = y; double y0 = y;
//noinspection RedundantCast Iterator<? extends TextParagraph<?,?,? extends TextRun>> paragraphs = getShape().iterator();
@SuppressWarnings("cast")
Iterator<? extends TextParagraph<?,?,? extends TextRun>> paragraphs =
(Iterator<? extends TextParagraph<?,?,? extends TextRun>>) getShape().iterator();
boolean isFirstLine = true; boolean isFirstLine = true;
for (int autoNbrIdx=0; paragraphs.hasNext(); autoNbrIdx++){ for (int autoNbrIdx=0; paragraphs.hasNext(); autoNbrIdx++){
@ -158,7 +155,9 @@ public class DrawTextShape extends DrawSimpleShape {
dp.setAutoNumberingIdx(autoNbrIdx); dp.setAutoNumberingIdx(autoNbrIdx);
dp.breakText(graphics); dp.breakText(graphics);
if (!isFirstLine) { if (isFirstLine) {
y += dp.getFirstLineLeading();
} else {
// the amount of vertical white space before the paragraph // the amount of vertical white space before the paragraph
Double spaceBefore = p.getSpaceBefore(); Double spaceBefore = p.getSpaceBefore();
if (spaceBefore == null) spaceBefore = 0d; if (spaceBefore == null) spaceBefore = 0d;
@ -221,7 +220,7 @@ public class DrawTextShape extends DrawSimpleShape {
} }
@Override @Override
protected TextShape<?,?> getShape() { protected TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getShape() {
return (TextShape<?,?>)shape; return (TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>)shape;
} }
} }

View File

@ -67,6 +67,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
} }
} }
@Override
public Iterator<XSLFTextParagraph> iterator(){ public Iterator<XSLFTextParagraph> iterator(){
return getTextParagraphs().iterator(); return getTextParagraphs().iterator();
} }
@ -75,7 +76,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public String getText() { public String getText() {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
for (XSLFTextParagraph p : _paragraphs) { for (XSLFTextParagraph p : _paragraphs) {
if (out.length() > 0) out.append('\n'); if (out.length() > 0) {
out.append('\n');
}
out.append(p.getText()); out.append(p.getText());
} }
return out.toString(); return out.toString();
@ -109,7 +112,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public XSLFTextRun appendText(String text, boolean newParagraph) { public XSLFTextRun appendText(String text, boolean newParagraph) {
if (text == null) return null; if (text == null) {
return null;
}
// copy properties from last paragraph / textrun or paragraph end marker // copy properties from last paragraph / textrun or paragraph end marker
CTTextParagraphProperties otherPPr = null; CTTextParagraphProperties otherPPr = null;
@ -202,7 +207,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(anchor == null) { if(anchor == null) {
if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor(); if(bodyPr.isSetAnchor()) {
bodyPr.unsetAnchor();
}
} else { } else {
bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1)); bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
} }
@ -212,6 +219,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public VerticalAlignment getVerticalAlignment(){ public VerticalAlignment getVerticalAlignment(){
PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){ PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetAnchor()){ if(props.isSetAnchor()){
int val = props.getAnchor().intValue(); int val = props.getAnchor().intValue();
@ -230,7 +238,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if (isCentered == null) { if (isCentered == null) {
if (bodyPr.isSetAnchorCtr()) bodyPr.unsetAnchorCtr(); if (bodyPr.isSetAnchorCtr()) {
bodyPr.unsetAnchorCtr();
}
} else { } else {
bodyPr.setAnchorCtr(isCentered); bodyPr.setAnchorCtr(isCentered);
} }
@ -240,6 +250,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public boolean isHorizontalCentered(){ public boolean isHorizontalCentered(){
PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetAnchorCtr()){ if(props.isSetAnchorCtr()){
setValue(props.getAnchorCtr()); setValue(props.getAnchorCtr());
@ -257,7 +268,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(orientation == null) { if(orientation == null) {
if(bodyPr.isSetVert()) bodyPr.unsetVert(); if(bodyPr.isSetVert()) {
bodyPr.unsetVert();
}
} else { } else {
bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1)); bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
} }
@ -315,6 +328,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
*/ */
public double getBottomInset(){ public double getBottomInset(){
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetBIns()){ if(props.isSetBIns()){
double val = Units.toPoints(props.getBIns()); double val = Units.toPoints(props.getBIns());
@ -338,6 +352,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
*/ */
public double getLeftInset(){ public double getLeftInset(){
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetLIns()){ if(props.isSetLIns()){
double val = Units.toPoints(props.getLIns()); double val = Units.toPoints(props.getLIns());
@ -361,6 +376,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
*/ */
public double getRightInset(){ public double getRightInset(){
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetRIns()){ if(props.isSetRIns()){
double val = Units.toPoints(props.getRIns()); double val = Units.toPoints(props.getRIns());
@ -383,6 +399,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
*/ */
public double getTopInset(){ public double getTopInset(){
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetTIns()){ if(props.isSetTIns()){
double val = Units.toPoints(props.getTIns()); double val = Units.toPoints(props.getTIns());
@ -406,8 +423,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public void setBottomInset(double margin){ public void setBottomInset(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(margin == -1) bodyPr.unsetBIns(); if(margin == -1) {
else bodyPr.setBIns(Units.toEMU(margin)); bodyPr.unsetBIns();
} else {
bodyPr.setBIns(Units.toEMU(margin));
}
} }
} }
@ -420,8 +440,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public void setLeftInset(double margin){ public void setLeftInset(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(margin == -1) bodyPr.unsetLIns(); if(margin == -1) {
else bodyPr.setLIns(Units.toEMU(margin)); bodyPr.unsetLIns();
} else {
bodyPr.setLIns(Units.toEMU(margin));
}
} }
} }
@ -434,8 +457,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public void setRightInset(double margin){ public void setRightInset(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(margin == -1) bodyPr.unsetRIns(); if(margin == -1) {
else bodyPr.setRIns(Units.toEMU(margin)); bodyPr.unsetRIns();
} else {
bodyPr.setRIns(Units.toEMU(margin));
}
} }
} }
@ -448,8 +474,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public void setTopInset(double margin){ public void setTopInset(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(margin == -1) bodyPr.unsetTIns(); if(margin == -1) {
else bodyPr.setTIns(Units.toEMU(margin)); bodyPr.unsetTIns();
} else {
bodyPr.setTIns(Units.toEMU(margin));
}
} }
} }
@ -470,6 +499,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public boolean getWordWrap(){ public boolean getWordWrap(){
PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
@Override
public boolean fetch(CTTextBodyProperties props){ public boolean fetch(CTTextBodyProperties props){
if(props.isSetWrap()){ if(props.isSetWrap()){
setValue(props.getWrap() == STTextWrappingType.SQUARE); setValue(props.getWrap() == STTextWrappingType.SQUARE);
@ -500,9 +530,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public void setTextAutofit(TextAutofit value){ public void setTextAutofit(TextAutofit value){
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
if (bodyPr != null) { if (bodyPr != null) {
if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit(); if(bodyPr.isSetSpAutoFit()) {
if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit(); bodyPr.unsetSpAutoFit();
if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit(); }
if(bodyPr.isSetNoAutofit()) {
bodyPr.unsetNoAutofit();
}
if(bodyPr.isSetNormAutofit()) {
bodyPr.unsetNormAutofit();
}
switch(value){ switch(value){
case NONE: bodyPr.addNewNoAutofit(); break; case NONE: bodyPr.addNewNoAutofit(); break;
@ -519,9 +555,13 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public TextAutofit getTextAutofit(){ public TextAutofit getTextAutofit(){
CTTextBodyProperties bodyPr = getTextBodyPr(); CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE; if(bodyPr.isSetNoAutofit()) {
else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL; return TextAutofit.NONE;
else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE; } else if (bodyPr.isSetNormAutofit()) {
return TextAutofit.NORMAL;
} else if (bodyPr.isSetSpAutoFit()) {
return TextAutofit.SHAPE;
}
} }
return TextAutofit.NORMAL; return TextAutofit.NORMAL;
} }
@ -551,7 +591,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
public Placeholder getTextType(){ public Placeholder getTextType(){
CTPlaceholder ph = getCTPlaceholder(); CTPlaceholder ph = getCTPlaceholder();
if (ph == null) return null; if (ph == null) {
return null;
}
int val = ph.getType().intValue(); int val = ph.getType().intValue();
return Placeholder.lookupOoxml(val); return Placeholder.lookupOoxml(val);
@ -571,12 +613,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
*/ */
public Rectangle2D resizeToFitText(){ public Rectangle2D resizeToFitText(){
Rectangle2D anchor = getAnchor(); Rectangle2D anchor = getAnchor();
if(anchor.getWidth() == 0.) throw new POIXMLException(
"Anchor of the shape was not set."); if(anchor.getWidth() == 0.) {
throw new POIXMLException("Anchor of the shape was not set.");
}
double height = getTextHeight(); double height = getTextHeight();
height += 1; // add a pixel to compensate rounding errors height += 1; // add a pixel to compensate rounding errors
anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height); Insets2D insets = getInsets();
anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height+insets.top+insets.bottom);
setAnchor(anchor); setAnchor(anchor);
return anchor; return anchor;
@ -596,7 +641,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy()); thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy());
if (thisTB.isSetLstStyle()) thisTB.unsetLstStyle(); if (thisTB.isSetLstStyle()) {
thisTB.unsetLstStyle();
}
if (otherTB.isSetLstStyle()) { if (otherTB.isSetLstStyle()) {
thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy()); thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy());
} }
@ -665,7 +712,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public TextPlaceholder getTextPlaceholder() { public TextPlaceholder getTextPlaceholder() {
Placeholder ph = getTextType(); Placeholder ph = getTextType();
if (ph == null) return TextPlaceholder.BODY; if (ph == null) {
return TextPlaceholder.BODY;
}
switch (ph) { switch (ph) {
case BODY: return TextPlaceholder.BODY; case BODY: return TextPlaceholder.BODY;
case TITLE: return TextPlaceholder.TITLE; case TITLE: return TextPlaceholder.TITLE;
@ -679,9 +728,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
* Helper method to allow subclasses to provide their own text paragraph * Helper method to allow subclasses to provide their own text paragraph
* *
* @param p the xml reference * @param p the xml reference
* *
* @return a new text paragraph * @return a new text paragraph
* *
* @since POI 3.15-beta2 * @since POI 3.15-beta2
*/ */
protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) { protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) {

View File

@ -329,7 +329,8 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
double height = getTextHeight(); double height = getTextHeight();
height += 1; // add a pixel to compensate rounding errors height += 1; // add a pixel to compensate rounding errors
anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height); Insets2D insets = getInsets();
anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height+insets.top+insets.bottom);
setAnchor(anchor); setAnchor(anchor);
return anchor; return anchor;