1 26 27 package it.stefanochizzolini.clown.documents.contents.composition; 28 29 import it.stefanochizzolini.clown.bytes.IBuffer; 30 import it.stefanochizzolini.clown.documents.contents.fonts.Font; 31 import it.stefanochizzolini.clown.objects.PdfReal; 32 33 import java.awt.geom.Dimension2D ; 34 import java.awt.geom.Point2D ; 35 import java.awt.geom.Rectangle2D ; 36 import java.util.ArrayList ; 37 import java.util.List ; 38 39 46 51 public class BlockFilter 52 { 53 private static class Row 56 { 57 60 public ArrayList <RowObject> objects = new ArrayList <RowObject>(); 61 64 public int spaceCount = 0; 65 68 public long beginPosition; 69 70 public double height; 71 74 public double y; 75 public double width; 76 77 Row( 78 long beginPosition, 79 double y 80 ) 81 { 82 this.beginPosition = beginPosition; 83 this.y = y; 84 } 85 } 86 87 private static class RowObject 88 { 89 public RowObjectTypeEnum type; 90 91 public long beginPosition; 92 93 public double height; 94 public double width; 95 96 public int spaceCount; 97 98 RowObject( 99 RowObjectTypeEnum type, 100 long beginPosition, 101 double height, 102 double width, 103 int spaceCount 104 ) 105 { 106 this.type = type; 107 this.beginPosition = beginPosition; 108 this.height = height; 109 this.width = width; 110 this.spaceCount = spaceCount; 111 } 112 } 113 114 private enum RowObjectTypeEnum 115 { 116 Text, 117 Image 118 } 119 121 142 private IBuffer buffer; 144 private ContentBuilder context; 145 146 private AlignmentXEnum alignmentX; 147 private AlignmentYEnum alignmentY; 148 private boolean hyphenation; 149 150 151 private Rectangle2D frame; 152 153 private Rectangle2D.Double boundBox; 154 155 156 private long beginPosition; 157 158 private Row currentRow; 159 private boolean rowEnded; 160 162 public BlockFilter( 164 ContentBuilder context 165 ) 166 { 167 this.context = context; 168 169 buffer = context.getBuffer(); 170 } 171 173 178 public void begin( 179 Rectangle2D frame, 180 AlignmentXEnum alignmentX, 181 AlignmentYEnum alignmentY 182 ) 183 { 184 this.frame = frame; 185 this.alignmentX = alignmentX; 186 this.alignmentY = alignmentY; 187 188 193 context.beginLocalState(); 194 195 beginPosition = buffer.getLength(); 196 197 boundBox = new Rectangle2D.Double ( 198 frame.getX(), 199 frame.getY(), 200 frame.getWidth(), 201 0 202 ); 203 204 beginRow(); 205 } 206 207 210 public void end( 211 ) 212 { 213 if(beginPosition < buffer.getLength()) 215 { 216 endRow(true); 218 219 buffer.insert( 221 (int)beginPosition, 222 "1 0 0 1 " 223 + PdfReal.toPdf(boundBox.x) + " " + PdfReal.toPdf(-boundBox.y) + " cm\r" 226 ); 227 } 228 229 context.endLocalState(); 231 } 232 233 236 public Rectangle2D getBoundBox( 237 ) 238 {return boundBox;} 239 240 243 public IBuffer getBuffer( 244 ) 245 {return buffer;} 246 247 250 public ContentBuilder getContext( 251 ) 252 {return context;} 253 254 257 public Rectangle2D getFrame( 258 ) 259 {return frame;} 260 261 264 public boolean getHyphenation( 265 ) 266 {return hyphenation;} 267 268 271 public void setHyphenation( 272 boolean value 273 ) 274 {hyphenation = value;} 275 276 279 public void showBreak( 280 ) 281 { 282 endRow(true); 283 beginRow(); 284 } 285 286 292 public void showBreak( 293 Dimension2D offset 294 ) 295 { 296 showBreak(); 297 298 currentRow.y += offset.getHeight(); 299 currentRow.width = offset.getWidth(); 300 } 301 302 306 public int showText( 307 String text 308 ) 309 { 310 if(currentRow == null 311 || text.trim().length() == 0) 312 return 0; 313 314 ContentBuilder.GraphicsState state = context.getState(); 315 Font font = state.getFont(); 316 double fontSize = state.getFontSize(); 317 TextFitter textFitter = new TextFitter( 318 text, 319 0, 320 font, 321 fontSize, 322 hyphenation 323 ); 324 int textLength = text.length(); 325 int index = 0; 326 double lineHeight = font.getLineHeight(fontSize); 327 while(true) 328 { 329 if(lineHeight > currentRow.height) 331 { 332 if(lineHeight > frame.getHeight() - currentRow.y) { 335 endRow(false); 337 338 return index; 339 } 340 else { 342 currentRow.height = lineHeight; 344 } 345 } 346 347 if(currentRow.width == 0) 349 { 350 while(text.charAt(index) == ' ') 352 { 353 if(index == textLength) 354 return index; 355 356 index++; 357 } 358 } 359 360 if(textFitter.fit( 362 index, 363 frame.getWidth() - currentRow.width )) 365 { 366 double textChunkWidth = textFitter.getFittedWidth(); 367 String textChunk = textFitter.getFittedText(); 368 Point2D textChunkLocation = new Point2D.Double ( 369 currentRow.width, 370 currentRow.y 371 ); 372 373 378 context.beginLocalState(); 379 380 RowObject object = new RowObject( 382 RowObjectTypeEnum.Text, 383 buffer.getLength(), 384 lineHeight, 385 textChunkWidth, 386 countOccurrence(' ',textChunk) 387 ); 388 currentRow.objects.add(object); 389 currentRow.spaceCount += object.spaceCount; 390 391 context.beginText(); 393 context.showText( 394 textChunk, 395 textChunkLocation 396 ); 397 context.endText(); 398 399 context.endLocalState(); 401 402 currentRow.width += textChunkWidth; 404 405 index = textFitter.getEndIndex(); 406 if(index == textLength) 408 break; 409 } 410 411 414 endRow(false); 415 beginRow(); 416 } 417 418 return index; 419 } 420 422 426 private void beginRow( 427 ) 428 { 429 rowEnded = false; 430 431 currentRow = new Row( 432 buffer.getLength(), 433 boundBox.height 434 ); 435 } 436 437 private int countOccurrence( 438 char value, 439 String text 440 ) 441 { 442 int count = 0; 443 int fromIndex = 0; 444 do 445 { 446 int foundIndex = text.indexOf(value,fromIndex); 447 if(foundIndex == -1) 448 return count; 449 450 count++; 451 452 fromIndex = foundIndex + 1; 453 } 454 while(true); 455 } 456 457 461 private void endRow( 462 boolean broken 463 ) 464 { 465 if(rowEnded) 466 return; 467 468 rowEnded = true; 469 470 double objectXOffsets[] = new double[currentRow.objects.size()]; double wordSpacing = 0; double rowXOffset = 0; 474 List <RowObject> objects = currentRow.objects; 475 476 AlignmentXEnum alignmentX = this.alignmentX; 478 switch(alignmentX) 479 { 480 case Left: 481 {break;} 482 case Right: 483 { 484 rowXOffset = frame.getWidth() - currentRow.width; 485 break; 486 } 487 case Center: 488 { 489 rowXOffset = (frame.getWidth() - currentRow.width) / 2; 490 break; 491 } 492 case Justify: 493 { 494 if(currentRow.spaceCount == 0 496 || broken) { 498 499 alignmentX = AlignmentXEnum.Left; 500 } 501 else { 503 wordSpacing = (frame.getWidth() - currentRow.width) / currentRow.spaceCount; 505 for( 507 int index = 1, 508 count = objects.size(); 509 index < count; 510 index++ 511 ) 512 { 513 517 objectXOffsets[index] = objectXOffsets[index - 1] + objects.get(index - 1).spaceCount * wordSpacing; 518 } 519 } 520 break; 521 } 522 } 523 524 for( 526 int index = objects.size() - 1; 527 index >= 0; 528 index-- 529 ) 530 { 531 RowObject object = objects.get(index); 532 533 double objectYOffset = 0; 535 switch(object.type) 536 { 537 case Text: 538 { 539 objectYOffset = -(currentRow.height - object.height); break; 541 } 542 case Image: 543 { 544 objectYOffset = -(currentRow.height - object.height) / 2; break; 546 } 547 } 548 549 553 buffer.insert( 554 (int)object.beginPosition, 555 "1 0 0 1 " 556 + PdfReal.toPdf(objectXOffsets[index] + rowXOffset) + " " + PdfReal.toPdf(objectYOffset) + " " + "cm\r" 559 ); 560 } 561 562 buffer.insert( 564 (int)currentRow.beginPosition, 565 PdfReal.toPdf(wordSpacing) + " Tw\r" 566 ); 567 568 boundBox.height = currentRow.y + currentRow.height; 570 571 double xOffset; 573 switch(alignmentY) 574 { 575 case Bottom: 576 xOffset = frame.getHeight() - boundBox.height; 577 break; 578 case Middle: 579 xOffset = (frame.getHeight() - boundBox.height) / 2; 580 break; 581 case Top: 582 default: 583 xOffset = 0; 584 break; 585 } 586 boundBox.y = frame.getY() + xOffset; 587 588 currentRow = null; 590 } 591 } | Popular Tags |