1 50 51 package com.lowagie.text.pdf; 52 53 import java.awt.Color ; 54 import java.util.HashMap ; 55 import java.util.Iterator ; 56 import java.util.Map ; 57 58 import com.lowagie.text.Chunk; 59 import com.lowagie.text.Font; 60 import com.lowagie.text.Image; 61 import com.lowagie.text.SplitCharacter; 62 import com.lowagie.text.Utilities; 63 64 74 75 public class PdfChunk implements SplitCharacter{ 76 77 private static final char singleSpace[] = {' '}; 78 private static final PdfChunk thisChunk[] = new PdfChunk[1]; 79 private static final float ITALIC_ANGLE = 0.21256f; 80 81 private static final HashMap keysAttributes = new HashMap (); 82 83 84 private static final HashMap keysNoStroke = new HashMap (); 85 86 static { 87 keysAttributes.put(Chunk.ACTION, null); 88 keysAttributes.put(Chunk.UNDERLINE, null); 89 keysAttributes.put(Chunk.REMOTEGOTO, null); 90 keysAttributes.put(Chunk.LOCALGOTO, null); 91 keysAttributes.put(Chunk.LOCALDESTINATION, null); 92 keysAttributes.put(Chunk.GENERICTAG, null); 93 keysAttributes.put(Chunk.NEWPAGE, null); 94 keysAttributes.put(Chunk.IMAGE, null); 95 keysAttributes.put(Chunk.BACKGROUND, null); 96 keysAttributes.put(Chunk.PDFANNOTATION, null); 97 keysAttributes.put(Chunk.SKEW, null); 98 keysAttributes.put(Chunk.HSCALE, null); 99 keysNoStroke.put(Chunk.SUBSUPSCRIPT, null); 100 keysNoStroke.put(Chunk.SPLITCHARACTER, null); 101 keysNoStroke.put(Chunk.HYPHENATION, null); 102 keysNoStroke.put(Chunk.TEXTRENDERMODE, null); 103 } 104 105 107 108 protected String value = PdfObject.NOTHING; 109 110 111 protected String encoding = BaseFont.WINANSI; 112 113 114 115 protected PdfFont font; 116 117 protected BaseFont baseFont; 118 119 protected SplitCharacter splitCharacter; 120 126 protected HashMap attributes = new HashMap (); 127 128 134 protected HashMap noStroke = new HashMap (); 135 136 137 protected boolean newlineSplit; 138 139 140 protected Image image; 141 142 143 protected float offsetX; 144 145 146 protected float offsetY; 147 148 149 protected boolean changeLeading = false; 150 151 153 159 160 PdfChunk(String string, PdfChunk other) { 161 thisChunk[0] = this; 162 value = string; 163 this.font = other.font; 164 this.attributes = other.attributes; 165 this.noStroke = other.noStroke; 166 this.baseFont = other.baseFont; 167 Object obj[] = (Object [])attributes.get(Chunk.IMAGE); 168 if (obj == null) 169 image = null; 170 else { 171 image = (Image)obj[0]; 172 offsetX = ((Float )obj[1]).floatValue(); 173 offsetY = ((Float )obj[2]).floatValue(); 174 changeLeading = ((Boolean )obj[3]).booleanValue(); 175 } 176 encoding = font.getFont().getEncoding(); 177 splitCharacter = (SplitCharacter)noStroke.get(Chunk.SPLITCHARACTER); 178 if (splitCharacter == null) 179 splitCharacter = this; 180 } 181 182 188 189 PdfChunk(Chunk chunk, PdfAction action) { 190 thisChunk[0] = this; 191 value = chunk.getContent(); 192 193 Font f = chunk.getFont(); 194 float size = f.getSize(); 195 if (size == Font.UNDEFINED) 196 size = 12; 197 baseFont = f.getBaseFont(); 198 int style = f.getStyle(); 199 if (style == Font.UNDEFINED) { 200 style = Font.NORMAL; 201 } 202 if (baseFont == null) { 203 baseFont = f.getCalculatedBaseFont(false); 205 } 206 else { 207 if ((style & Font.BOLD) != 0) 209 attributes.put(Chunk.TEXTRENDERMODE, new Object []{new Integer (PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE), new Float (size / 30f), null}); 210 if ((style & Font.ITALIC) != 0) 212 attributes.put(Chunk.SKEW, new float[]{0, ITALIC_ANGLE}); 213 } 214 font = new PdfFont(baseFont, size); 215 HashMap attr = chunk.getAttributes(); 217 if (attr != null) { 218 for (Iterator i = attr.entrySet().iterator(); i.hasNext();) { 219 Map.Entry entry = (Map.Entry ) i.next(); 220 Object name = entry.getKey(); 221 if (keysAttributes.containsKey(name)) { 222 attributes.put(name, entry.getValue()); 223 } 224 else if (keysNoStroke.containsKey(name)) { 225 noStroke.put(name, entry.getValue()); 226 } 227 } 228 if ("".equals(attr.get(Chunk.GENERICTAG))) { 229 attributes.put(Chunk.GENERICTAG, chunk.getContent()); 230 } 231 } 232 if (f.isUnderlined()) { 233 Object obj[] = {null, new float[]{0, 1f / 15, 0, -1f / 3, 0}}; 234 Object unders[][] = Utilities.addToArray((Object [][])attributes.get(Chunk.UNDERLINE), obj); 235 attributes.put(Chunk.UNDERLINE, unders); 236 } 237 if (f.isStrikethru()) { 238 Object obj[] = {null, new float[]{0, 1f / 15, 0, 1f / 3, 0}}; 239 Object unders[][] = Utilities.addToArray((Object [][])attributes.get(Chunk.UNDERLINE), obj); 240 attributes.put(Chunk.UNDERLINE, unders); 241 } 242 if (action != null) 243 attributes.put(Chunk.ACTION, action); 244 noStroke.put(Chunk.COLOR, f.getColor()); 246 noStroke.put(Chunk.ENCODING, font.getFont().getEncoding()); 247 Object obj[] = (Object [])attributes.get(Chunk.IMAGE); 248 if (obj == null) { 249 image = null; 250 } 251 else { 252 attributes.remove(Chunk.HSCALE); image = (Image)obj[0]; 254 offsetX = ((Float )obj[1]).floatValue(); 255 offsetY = ((Float )obj[2]).floatValue(); 256 changeLeading = ((Boolean )obj[3]).booleanValue(); 257 } 258 font.setImage(image); 259 Float hs = (Float )attributes.get(Chunk.HSCALE); 260 if (hs != null) 261 font.setHorizontalScaling(hs.floatValue()); 262 encoding = font.getFont().getEncoding(); 263 splitCharacter = (SplitCharacter)noStroke.get(Chunk.SPLITCHARACTER); 264 if (splitCharacter == null) 265 splitCharacter = this; 266 } 267 268 270 276 public char getUnicodeEquivalent(char c) { 277 return baseFont.getUnicodeEquivalent(c); 278 } 279 280 protected int getWord(String text, int start) { 281 int len = text.length(); 282 while (start < len) { 283 if (!Character.isLetter(text.charAt(start))) 284 break; 285 ++start; 286 } 287 return start; 288 } 289 290 298 299 PdfChunk split(float width) { 300 newlineSplit = false; 301 if (image != null) { 302 if (image.getScaledWidth() > width) { 303 PdfChunk pc = new PdfChunk(Chunk.OBJECT_REPLACEMENT_CHARACTER, this); 304 value = ""; 305 attributes = new HashMap (); 306 image = null; 307 font = PdfFont.getDefaultFont(); 308 return pc; 309 } 310 else 311 return null; 312 } 313 HyphenationEvent hyphenationEvent = (HyphenationEvent)noStroke.get(Chunk.HYPHENATION); 314 int currentPosition = 0; 315 int splitPosition = -1; 316 float currentWidth = 0; 317 318 int lastSpace = -1; 321 float lastSpaceWidth = 0; 322 int length = value.length(); 323 char valueArray[] = value.toCharArray(); 324 char character = 0; 325 BaseFont ft = font.getFont(); 326 if (ft.getFontType() == BaseFont.FONT_TYPE_CJK && ft.getUnicodeEquivalent(' ') != ' ') { 327 while (currentPosition < length) { 328 char cidChar = valueArray[currentPosition]; 330 character = ft.getUnicodeEquivalent(cidChar); 331 if (character == '\n') { 333 newlineSplit = true; 334 String returnValue = value.substring(currentPosition + 1); 335 value = value.substring(0, currentPosition); 336 if (value.length() < 1) { 337 value = "\u0001"; 338 } 339 PdfChunk pc = new PdfChunk(returnValue, this); 340 return pc; 341 } 342 currentWidth += font.width(cidChar); 343 if (character == ' ') { 344 lastSpace = currentPosition + 1; 345 lastSpaceWidth = currentWidth; 346 } 347 if (currentWidth > width) 348 break; 349 if (splitCharacter.isSplitCharacter(0, currentPosition, length, valueArray, thisChunk)) 351 splitPosition = currentPosition + 1; 352 currentPosition++; 353 } 354 } 355 else { 356 while (currentPosition < length) { 357 character = valueArray[currentPosition]; 359 if (character == '\r' || character == '\n') { 361 newlineSplit = true; 362 int inc = 1; 363 if (character == '\r' && currentPosition + 1 < length && valueArray[currentPosition + 1] == '\n') 364 inc = 2; 365 String returnValue = value.substring(currentPosition + inc); 366 value = value.substring(0, currentPosition); 367 if (value.length() < 1) { 368 value = " "; 369 } 370 PdfChunk pc = new PdfChunk(returnValue, this); 371 return pc; 372 } 373 currentWidth += font.width(character); 374 if (character == ' ') { 375 lastSpace = currentPosition + 1; 376 lastSpaceWidth = currentWidth; 377 } 378 if (currentWidth > width) 379 break; 380 if (splitCharacter.isSplitCharacter(0, currentPosition, length, valueArray, null)) 382 splitPosition = currentPosition + 1; 383 currentPosition++; 384 } 385 } 386 387 if (currentPosition == length) { 389 return null; 390 } 391 if (splitPosition < 0) { 393 String returnValue = value; 394 value = ""; 395 PdfChunk pc = new PdfChunk(returnValue, this); 396 return pc; 397 } 398 if (lastSpace > splitPosition && splitCharacter.isSplitCharacter(0, 0, 1, singleSpace, null)) 399 splitPosition = lastSpace; 400 if (hyphenationEvent != null && lastSpace >= 0 && lastSpace < currentPosition) { 401 int wordIdx = getWord(value, lastSpace); 402 if (wordIdx > lastSpace) { 403 String pre = hyphenationEvent.getHyphenatedWordPre(value.substring(lastSpace, wordIdx), font.getFont(), font.size(), width - lastSpaceWidth); 404 String post = hyphenationEvent.getHyphenatedWordPost(); 405 if (pre.length() > 0) { 406 String returnValue = post + value.substring(wordIdx); 407 value = trim(value.substring(0, lastSpace) + pre); 408 PdfChunk pc = new PdfChunk(returnValue, this); 409 return pc; 410 } 411 } 412 } 413 String returnValue = value.substring(splitPosition); 414 value = trim(value.substring(0, splitPosition)); 415 PdfChunk pc = new PdfChunk(returnValue, this); 416 return pc; 417 } 418 419 427 428 PdfChunk truncate(float width) { 429 if (image != null) { 430 if (image.getScaledWidth() > width) { 431 PdfChunk pc = new PdfChunk("", this); 432 value = ""; 433 attributes.remove(Chunk.IMAGE); 434 image = null; 435 font = PdfFont.getDefaultFont(); 436 return pc; 437 } 438 else 439 return null; 440 } 441 442 int currentPosition = 0; 443 float currentWidth = 0; 444 445 if (width < font.width()) { 447 String returnValue = value.substring(1); 448 value = value.substring(0, 1); 449 PdfChunk pc = new PdfChunk(returnValue, this); 450 return pc; 451 } 452 453 int length = value.length(); 456 char character; 457 while (currentPosition < length) { 458 character = value.charAt(currentPosition); 460 currentWidth += font.width(character); 461 if (currentWidth > width) 462 break; 463 currentPosition++; 464 } 465 466 if (currentPosition == length) { 468 return null; 469 } 470 471 if (currentPosition == 0) { 475 currentPosition = 1; 476 } 477 String returnValue = value.substring(currentPosition); 478 value = value.substring(0, currentPosition); 479 PdfChunk pc = new PdfChunk(returnValue, this); 480 return pc; 481 } 482 483 485 490 491 PdfFont font() { 492 return font; 493 } 494 495 500 501 Color color() { 502 return (Color )noStroke.get(Chunk.COLOR); 503 } 504 505 510 511 float width() { 512 return font.width(value); 513 } 514 515 519 520 public boolean isNewlineSplit() 521 { 522 return newlineSplit; 523 } 524 525 532 533 public float getWidthCorrected(float charSpacing, float wordSpacing) 534 { 535 if (image != null) { 536 return image.getScaledWidth() + charSpacing; 537 } 538 int numberOfSpaces = 0; 539 int idx = -1; 540 while ((idx = value.indexOf(' ', idx + 1)) >= 0) 541 ++numberOfSpaces; 542 return width() + (value.length() * charSpacing + numberOfSpaces * wordSpacing); 543 } 544 545 549 public float getTextRise() { 550 Float f = (Float ) getAttribute(Chunk.SUBSUPSCRIPT); 551 if (f != null) { 552 return f.floatValue(); 553 } 554 return 0.0f; 555 } 556 557 561 562 public float trimLastSpace() 563 { 564 BaseFont ft = font.getFont(); 565 if (ft.getFontType() == BaseFont.FONT_TYPE_CJK && ft.getUnicodeEquivalent(' ') != ' ') { 566 if (value.length() > 1 && value.endsWith("\u0001")) { 567 value = value.substring(0, value.length() - 1); 568 return font.width('\u0001'); 569 } 570 } 571 else { 572 if (value.length() > 1 && value.endsWith(" ")) { 573 value = value.substring(0, value.length() - 1); 574 return font.width(' '); 575 } 576 } 577 return 0; 578 } 579 public float trimFirstSpace() 580 { 581 BaseFont ft = font.getFont(); 582 if (ft.getFontType() == BaseFont.FONT_TYPE_CJK && ft.getUnicodeEquivalent(' ') != ' ') { 583 if (value.length() > 1 && value.startsWith("\u0001")) { 584 value = value.substring(1); 585 return font.width('\u0001'); 586 } 587 } 588 else { 589 if (value.length() > 1 && value.startsWith(" ")) { 590 value = value.substring(1); 591 return font.width(' '); 592 } 593 } 594 return 0; 595 } 596 597 603 604 Object getAttribute(String name) 605 { 606 if (attributes.containsKey(name)) 607 return attributes.get(name); 608 return noStroke.get(name); 609 } 610 611 616 617 boolean isAttribute(String name) 618 { 619 if (attributes.containsKey(name)) 620 return true; 621 return noStroke.containsKey(name); 622 } 623 624 628 629 boolean isStroked() 630 { 631 return (!attributes.isEmpty()); 632 } 633 634 638 639 boolean isImage() 640 { 641 return image != null; 642 } 643 644 648 649 Image getImage() 650 { 651 return image; 652 } 653 654 658 659 void setImageOffsetX(float offsetX) 660 { 661 this.offsetX = offsetX; 662 } 663 664 668 669 float getImageOffsetX() 670 { 671 return offsetX; 672 } 673 674 678 679 void setImageOffsetY(float offsetY) 680 { 681 this.offsetY = offsetY; 682 } 683 684 688 689 float getImageOffsetY() 690 { 691 return offsetY; 692 } 693 694 698 699 void setValue(String value) 700 { 701 this.value = value; 702 } 703 704 707 public String toString() { 708 return value; 709 } 710 711 715 716 boolean isSpecialEncoding() { 717 return encoding.equals(CJKFont.CJK_ENCODING) || encoding.equals(BaseFont.IDENTITY_H); 718 } 719 720 725 726 String getEncoding() { 727 return encoding; 728 } 729 730 int length() { 731 return value.length(); 732 } 733 745 public boolean isSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { 746 char c; 747 if (ck == null) 748 c = cc[current]; 749 else 750 c = ck[Math.min(current, ck.length - 1)].getUnicodeEquivalent(cc[current]); 751 if (c <= ' ' || c == '-') { 752 return true; 753 } 754 if (c < 0x2e80) 755 return false; 756 return ((c >= 0x2e80 && c < 0xd7a0) 757 || (c >= 0xf900 && c < 0xfb00) 758 || (c >= 0xfe30 && c < 0xfe50) 759 || (c >= 0xff61 && c < 0xffa0)); 760 } 761 762 boolean isExtSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { 763 return splitCharacter.isSplitCharacter(start, current, end, cc, ck); 764 } 765 766 772 String trim(String string) { 773 BaseFont ft = font.getFont(); 774 if (ft.getFontType() == BaseFont.FONT_TYPE_CJK && ft.getUnicodeEquivalent(' ') != ' ') { 775 while (string.endsWith("\u0001")) { 776 string = string.substring(0, string.length() - 1); 777 } 778 } 779 else { 780 while (string.endsWith(" ") || string.endsWith("\t")) { 781 string = string.substring(0, string.length() - 1); 782 } 783 } 784 return string; 785 } 786 787 public boolean changeLeading() { 788 return changeLeading; 789 } 790 791 float getCharWidth(char c) { 792 if (noPrint(c)) 793 return 0; 794 return font.width(c); 795 } 796 797 public static boolean noPrint(char c) { 798 return ((c >= 0x200b && c <= 0x200f) || (c >= 0x202a && c <= 0x202e)); 799 } 800 801 } 802 | Popular Tags |