1 28 package net.sf.jasperreports.engine.fill; 29 30 import java.awt.font.FontRenderContext ; 31 import java.awt.font.LineBreakMeasurer ; 32 import java.awt.font.TextLayout ; 33 import java.text.AttributedCharacterIterator ; 34 import java.text.AttributedString ; 35 import java.util.StringTokenizer ; 36 37 import net.sf.jasperreports.engine.JRTextElement; 38 import net.sf.jasperreports.engine.export.TextRenderer; 39 import net.sf.jasperreports.engine.util.JRStyledText; 40 import net.sf.jasperreports.engine.util.MaxFontSizeFinder; 41 42 43 47 public class TextMeasurer 48 { 49 50 53 private static final FontRenderContext FONT_RENDER_CONTEXT = TextRenderer.LINE_BREAK_FONT_RENDER_CONTEXT; 54 55 58 private JRTextElement textElement = null; 59 60 61 64 private MaxFontSizeFinder maxFontSizeFinder = null; 65 66 private int width = 0; 67 private int height = 0; 68 private int topPadding = 0; 69 private int leftPadding = 0; 70 private int bottomPadding = 0; 71 private int rightPadding = 0; 72 private float lineSpacing = 0; 73 74 private float formatWidth = 0; 75 private int maxHeight = 0; 76 private int textOffset = 0; 77 private int lines = 0; 78 private int fontSizeSum = 0; 79 private int firstLineMaxFontSize = 0; 80 private float textHeight = 0; 81 private float firstLineLeading = 0; 82 private boolean isLeftToRight = true; 83 private boolean isMaxHeightReached = false; 84 85 86 89 public TextMeasurer(JRTextElement textElement) 90 { 91 this.textElement = textElement; 92 } 93 94 97 private void initialize(int availableStretchHeight) 98 { 99 width = textElement.getWidth(); 100 height = textElement.getHeight(); 101 102 topPadding = textElement.getTopPadding(); 103 leftPadding = textElement.getLeftPadding(); 104 bottomPadding = textElement.getBottomPadding(); 105 rightPadding = textElement.getRightPadding(); 106 107 switch (textElement.getRotation()) 108 { 109 case JRTextElement.ROTATION_LEFT : 110 { 111 width = textElement.getHeight(); 112 height = textElement.getWidth(); 113 int tmpPadding = topPadding; 114 topPadding = leftPadding; 115 leftPadding = bottomPadding; 116 bottomPadding = rightPadding; 117 rightPadding = tmpPadding; 118 break; 119 } 120 case JRTextElement.ROTATION_RIGHT : 121 { 122 width = textElement.getHeight(); 123 height = textElement.getWidth(); 124 int tmpPadding = topPadding; 125 topPadding = rightPadding; 126 rightPadding = bottomPadding; 127 bottomPadding = leftPadding; 128 leftPadding = tmpPadding; 129 break; 130 } 131 case JRTextElement.ROTATION_UPSIDE_DOWN : 132 { 133 int tmpPadding = topPadding; 134 topPadding = bottomPadding; 135 bottomPadding = tmpPadding; 136 tmpPadding = leftPadding; 137 leftPadding = rightPadding; 138 rightPadding = tmpPadding; 139 break; 140 } 141 case JRTextElement.ROTATION_NONE : 142 default : 143 { 144 } 145 } 146 147 148 switch (textElement.getLineSpacing()) 149 { 150 case JRTextElement.LINE_SPACING_SINGLE : 151 { 152 lineSpacing = 1f; 153 break; 154 } 155 case JRTextElement.LINE_SPACING_1_1_2 : 156 { 157 lineSpacing = 1.5f; 158 break; 159 } 160 case JRTextElement.LINE_SPACING_DOUBLE : 161 { 162 lineSpacing = 2f; 163 break; 164 } 165 default : 166 { 167 lineSpacing = 1f; 168 } 169 } 170 171 maxFontSizeFinder = MaxFontSizeFinder.getInstance(textElement.isStyledText()); 172 173 formatWidth = width - leftPadding - rightPadding; 174 formatWidth = formatWidth < 0 ? 0 : formatWidth; 175 maxHeight = height + availableStretchHeight - topPadding - bottomPadding; 176 maxHeight = maxHeight < 0 ? 0 : maxHeight; 177 textOffset = 0; 178 lines = 0; 179 fontSizeSum = 0; 180 firstLineMaxFontSize = 0; 181 textHeight = 0; 182 firstLineLeading = 0; 183 isLeftToRight = true; 184 isMaxHeightReached = false; 185 } 186 187 190 public void measure( 191 JRStyledText styledText, 192 String remainingText, 193 int remainingTextStart, 194 int availableStretchHeight 195 ) 196 { 197 198 initialize(availableStretchHeight); 199 200 AttributedCharacterIterator allParagraphs = styledText.getAttributedString().getIterator(); 201 202 int tokenPosition = remainingTextStart; 203 int lastParagraphStart = remainingTextStart; 204 String lastParagraphText = null; 205 206 StringTokenizer tkzer = new StringTokenizer (remainingText, "\n", true); 207 208 while(tkzer.hasMoreTokens() && !isMaxHeightReached) 209 { 210 String token = tkzer.nextToken(); 211 212 if ("\n".equals(token)) 213 { 214 renderParagraph(allParagraphs, lastParagraphStart, lastParagraphText); 215 216 lastParagraphStart = tokenPosition + (tkzer.hasMoreTokens() || tokenPosition == 0 ? 1 : 0); 217 lastParagraphText = null; 218 } 219 else 220 { 221 lastParagraphStart = tokenPosition; 222 lastParagraphText = token; 223 } 224 225 tokenPosition += token.length(); 226 } 227 228 if (!isMaxHeightReached && lastParagraphStart < remainingTextStart + remainingText.length()) 229 { 230 renderParagraph(allParagraphs, lastParagraphStart, lastParagraphText); 231 } 232 } 233 234 237 private void renderParagraph( 238 AttributedCharacterIterator allParagraphs, 239 int lastParagraphStart, 240 String lastParagraphText 241 ) 242 { 243 AttributedCharacterIterator paragraph = null; 244 245 if (lastParagraphText == null) 246 { 247 paragraph = 248 new AttributedString ( 249 " ", 250 new AttributedString ( 251 allParagraphs, 252 lastParagraphStart, 253 lastParagraphStart + 1 254 ).getIterator().getAttributes() 255 ).getIterator(); 256 } 257 else 258 { 259 paragraph = 260 new AttributedString ( 261 allParagraphs, 262 lastParagraphStart, 263 lastParagraphStart + lastParagraphText.length() 264 ).getIterator(); 265 } 266 267 int positionWithinParagraph = 0; 268 269 LineBreakMeasurer lineMeasurer = new LineBreakMeasurer (paragraph, FONT_RENDER_CONTEXT); 270 271 while (lineMeasurer.getPosition() < paragraph.getEndIndex() && !isMaxHeightReached) 272 { 273 int lineStartPosition = lineMeasurer.getPosition(); 274 275 TextLayout layout = lineMeasurer.nextLayout(formatWidth); 276 277 isLeftToRight = isLeftToRight && layout.isLeftToRight(); 278 279 textHeight += layout.getLeading() + lineSpacing * layout.getAscent(); 280 281 if (textHeight + layout.getDescent() <= maxHeight) 282 { 283 lines++; 284 285 fontSizeSum += 286 maxFontSizeFinder.findMaxFontSize( 287 new AttributedString ( 288 paragraph, 289 lineStartPosition, 290 lineStartPosition + layout.getCharacterCount() 291 ).getIterator(), 292 textElement.getFontSize() 293 ); 294 295 if (lines == 1) 296 { 297 firstLineLeading = textHeight; 298 firstLineMaxFontSize = fontSizeSum; 299 } 300 301 positionWithinParagraph = lineMeasurer.getPosition(); 302 textHeight += layout.getDescent(); 306 } 307 else 308 { 309 textHeight -= layout.getLeading() + lineSpacing * layout.getAscent(); 310 isMaxHeightReached = true; 311 } 312 } 313 314 textOffset = lastParagraphStart + positionWithinParagraph; } 316 317 318 321 protected boolean isLeftToRight() 322 { 323 return isLeftToRight; 324 } 325 326 329 protected int getTextOffset() 330 { 331 return textOffset; 332 } 333 334 337 public float getTextHeight() 338 { 339 return textHeight; 340 } 341 342 345 public float getLineSpacingFactor() 346 { 347 if (lines > 0) 348 { 349 return textHeight / fontSizeSum; 350 } 351 return 0; 352 } 353 354 357 public float getLeadingOffset() 358 { 359 return firstLineLeading - firstLineMaxFontSize * getLineSpacingFactor(); 360 } 361 362 } 363 | Popular Tags |