001: /*
002: * $Id: PdfChunk.java 2742 2007-05-08 13:04:56Z blowagie $
003: * $Name$
004: *
005: * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
022: *
023: * Contributor(s): all the names of the contributors are added in the source code
024: * where applicable.
025: *
026: * Alternatively, the contents of this file may be used under the terms of the
027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
028: * provisions of LGPL are applicable instead of those above. If you wish to
029: * allow use of your version of this file only under the terms of the LGPL
030: * License and not to allow others to use your version of this file under
031: * the MPL, indicate your decision by deleting the provisions above and
032: * replace them with the notice and other provisions required by the LGPL.
033: * If you do not delete the provisions above, a recipient may use your version
034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
035: *
036: * This library is free software; you can redistribute it and/or modify it
037: * under the terms of the MPL as stated above or under the terms of the GNU
038: * Library General Public License as published by the Free Software Foundation;
039: * either version 2 of the License, or any later version.
040: *
041: * This library is distributed in the hope that it will be useful, but WITHOUT
042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
044: * details.
045: *
046: * If you didn't download this code from the following link, you should check if
047: * you aren't using an obsolete version:
048: * http://www.lowagie.com/iText/
049: */
050:
051: package com.lowagie.text.pdf;
052:
053: import java.awt.Color;
054: import java.util.HashMap;
055: import java.util.Iterator;
056: import java.util.Map;
057:
058: import com.lowagie.text.Chunk;
059: import com.lowagie.text.Font;
060: import com.lowagie.text.Image;
061: import com.lowagie.text.SplitCharacter;
062: import com.lowagie.text.Utilities;
063:
064: /**
065: * A <CODE>PdfChunk</CODE> is the PDF translation of a <CODE>Chunk</CODE>.
066: * <P>
067: * A <CODE>PdfChunk</CODE> is a <CODE>PdfString</CODE> in a certain
068: * <CODE>PdfFont</CODE> and <CODE>Color</CODE>.
069: *
070: * @see PdfString
071: * @see com.lowagie.text.Chunk
072: * @see com.lowagie.text.Font
073: */
074:
075: public class PdfChunk implements SplitCharacter {
076:
077: private static final char singleSpace[] = { ' ' };
078: private static final PdfChunk this Chunk[] = new PdfChunk[1];
079: private static final float ITALIC_ANGLE = 0.21256f;
080: /** The allowed attributes in variable <CODE>attributes</CODE>. */
081: private static final HashMap keysAttributes = new HashMap();
082:
083: /** The allowed attributes in variable <CODE>noStroke</CODE>. */
084: private static final HashMap keysNoStroke = new HashMap();
085:
086: static {
087: keysAttributes.put(Chunk.ACTION, null);
088: keysAttributes.put(Chunk.UNDERLINE, null);
089: keysAttributes.put(Chunk.REMOTEGOTO, null);
090: keysAttributes.put(Chunk.LOCALGOTO, null);
091: keysAttributes.put(Chunk.LOCALDESTINATION, null);
092: keysAttributes.put(Chunk.GENERICTAG, null);
093: keysAttributes.put(Chunk.NEWPAGE, null);
094: keysAttributes.put(Chunk.IMAGE, null);
095: keysAttributes.put(Chunk.BACKGROUND, null);
096: keysAttributes.put(Chunk.PDFANNOTATION, null);
097: keysAttributes.put(Chunk.SKEW, null);
098: keysAttributes.put(Chunk.HSCALE, null);
099: 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: // membervariables
106:
107: /** The value of this object. */
108: protected String value = PdfObject.NOTHING;
109:
110: /** The encoding. */
111: protected String encoding = BaseFont.WINANSI;
112:
113: /** The font for this <CODE>PdfChunk</CODE>. */
114: protected PdfFont font;
115:
116: protected BaseFont baseFont;
117:
118: protected SplitCharacter splitCharacter;
119: /**
120: * Metric attributes.
121: * <P>
122: * This attributes require the mesurement of characters widths when rendering
123: * such as underline.
124: */
125: protected HashMap attributes = new HashMap();
126:
127: /**
128: * Non metric attributes.
129: * <P>
130: * This attributes do not require the mesurement of characters widths when rendering
131: * such as Color.
132: */
133: protected HashMap noStroke = new HashMap();
134:
135: /** <CODE>true</CODE> if the chunk split was cause by a newline. */
136: protected boolean newlineSplit;
137:
138: /** The image in this <CODE>PdfChunk</CODE>, if it has one */
139: protected Image image;
140:
141: /** The offset in the x direction for the image */
142: protected float offsetX;
143:
144: /** The offset in the y direction for the image */
145: protected float offsetY;
146:
147: /** Indicates if the height and offset of the Image has to be taken into account */
148: protected boolean changeLeading = false;
149:
150: // constructors
151:
152: /**
153: * Constructs a <CODE>PdfChunk</CODE>-object.
154: *
155: * @param string the content of the <CODE>PdfChunk</CODE>-object
156: * @param other Chunk with the same style you want for the new Chunk
157: */
158:
159: PdfChunk(String string, PdfChunk other) {
160: this Chunk[0] = this ;
161: value = string;
162: this .font = other.font;
163: this .attributes = other.attributes;
164: this .noStroke = other.noStroke;
165: this .baseFont = other.baseFont;
166: Object obj[] = (Object[]) attributes.get(Chunk.IMAGE);
167: if (obj == null)
168: image = null;
169: else {
170: image = (Image) obj[0];
171: offsetX = ((Float) obj[1]).floatValue();
172: offsetY = ((Float) obj[2]).floatValue();
173: changeLeading = ((Boolean) obj[3]).booleanValue();
174: }
175: encoding = font.getFont().getEncoding();
176: splitCharacter = (SplitCharacter) noStroke
177: .get(Chunk.SPLITCHARACTER);
178: if (splitCharacter == null)
179: splitCharacter = this ;
180: }
181:
182: /**
183: * Constructs a <CODE>PdfChunk</CODE>-object.
184: *
185: * @param chunk the original <CODE>Chunk</CODE>-object
186: * @param action the <CODE>PdfAction</CODE> if the <CODE>Chunk</CODE> comes from an <CODE>Anchor</CODE>
187: */
188:
189: PdfChunk(Chunk chunk, PdfAction action) {
190: this Chunk[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: // translation of the font-family to a PDF font-family
204: baseFont = f.getCalculatedBaseFont(false);
205: } else {
206: // bold simulation
207: if ((style & Font.BOLD) != 0)
208: attributes
209: .put(
210: Chunk.TEXTRENDERMODE,
211: new Object[] {
212: new Integer(
213: PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE),
214: new Float(size / 30f), null });
215: // italic simulation
216: if ((style & Font.ITALIC) != 0)
217: attributes.put(Chunk.SKEW, new float[] { 0,
218: ITALIC_ANGLE });
219: }
220: font = new PdfFont(baseFont, size);
221: // other style possibilities
222: HashMap attr = chunk.getAttributes();
223: if (attr != null) {
224: for (Iterator i = attr.entrySet().iterator(); i.hasNext();) {
225: Map.Entry entry = (Map.Entry) i.next();
226: Object name = entry.getKey();
227: if (keysAttributes.containsKey(name)) {
228: attributes.put(name, entry.getValue());
229: } else if (keysNoStroke.containsKey(name)) {
230: noStroke.put(name, entry.getValue());
231: }
232: }
233: if ("".equals(attr.get(Chunk.GENERICTAG))) {
234: attributes.put(Chunk.GENERICTAG, chunk.getContent());
235: }
236: }
237: if (f.isUnderlined()) {
238: Object obj[] = { null,
239: new float[] { 0, 1f / 15, 0, -1f / 3, 0 } };
240: Object unders[][] = Utilities.addToArray(
241: (Object[][]) attributes.get(Chunk.UNDERLINE), obj);
242: attributes.put(Chunk.UNDERLINE, unders);
243: }
244: if (f.isStrikethru()) {
245: Object obj[] = { null,
246: new float[] { 0, 1f / 15, 0, 1f / 3, 0 } };
247: Object unders[][] = Utilities.addToArray(
248: (Object[][]) attributes.get(Chunk.UNDERLINE), obj);
249: attributes.put(Chunk.UNDERLINE, unders);
250: }
251: if (action != null)
252: attributes.put(Chunk.ACTION, action);
253: // the color can't be stored in a PdfFont
254: noStroke.put(Chunk.COLOR, f.getColor());
255: noStroke.put(Chunk.ENCODING, font.getFont().getEncoding());
256: Object obj[] = (Object[]) attributes.get(Chunk.IMAGE);
257: if (obj == null) {
258: image = null;
259: } else {
260: attributes.remove(Chunk.HSCALE); // images are scaled in other ways
261: image = (Image) obj[0];
262: offsetX = ((Float) obj[1]).floatValue();
263: offsetY = ((Float) obj[2]).floatValue();
264: changeLeading = ((Boolean) obj[3]).booleanValue();
265: }
266: font.setImage(image);
267: Float hs = (Float) attributes.get(Chunk.HSCALE);
268: if (hs != null)
269: font.setHorizontalScaling(hs.floatValue());
270: encoding = font.getFont().getEncoding();
271: splitCharacter = (SplitCharacter) noStroke
272: .get(Chunk.SPLITCHARACTER);
273: if (splitCharacter == null)
274: splitCharacter = this ;
275: }
276:
277: // methods
278:
279: /** Gets the Unicode equivalent to a CID.
280: * The (inexistent) CID <FF00> is translated as '\n'.
281: * It has only meaning with CJK fonts with Identity encoding.
282: * @param c the CID code
283: * @return the Unicode equivalent
284: */
285: public char getUnicodeEquivalent(char c) {
286: return baseFont.getUnicodeEquivalent(c);
287: }
288:
289: protected int getWord(String text, int start) {
290: int len = text.length();
291: while (start < len) {
292: if (!Character.isLetter(text.charAt(start)))
293: break;
294: ++start;
295: }
296: return start;
297: }
298:
299: /**
300: * Splits this <CODE>PdfChunk</CODE> if it's too long for the given width.
301: * <P>
302: * Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated.
303: *
304: * @param width a given width
305: * @return the <CODE>PdfChunk</CODE> that doesn't fit into the width.
306: */
307:
308: PdfChunk split(float width) {
309: newlineSplit = false;
310: if (image != null) {
311: if (image.getScaledWidth() > width) {
312: PdfChunk pc = new PdfChunk(
313: Chunk.OBJECT_REPLACEMENT_CHARACTER, this );
314: value = "";
315: attributes = new HashMap();
316: image = null;
317: font = PdfFont.getDefaultFont();
318: return pc;
319: } else
320: return null;
321: }
322: HyphenationEvent hyphenationEvent = (HyphenationEvent) noStroke
323: .get(Chunk.HYPHENATION);
324: int currentPosition = 0;
325: int splitPosition = -1;
326: float currentWidth = 0;
327:
328: // loop over all the characters of a string
329: // or until the totalWidth is reached
330: int lastSpace = -1;
331: float lastSpaceWidth = 0;
332: int length = value.length();
333: char valueArray[] = value.toCharArray();
334: char character = 0;
335: BaseFont ft = font.getFont();
336: if (ft.getFontType() == BaseFont.FONT_TYPE_CJK
337: && ft.getUnicodeEquivalent(' ') != ' ') {
338: while (currentPosition < length) {
339: // the width of every character is added to the currentWidth
340: char cidChar = valueArray[currentPosition];
341: character = ft.getUnicodeEquivalent(cidChar);
342: // if a newLine or carriageReturn is encountered
343: if (character == '\n') {
344: newlineSplit = true;
345: String returnValue = value
346: .substring(currentPosition + 1);
347: value = value.substring(0, currentPosition);
348: if (value.length() < 1) {
349: value = "\u0001";
350: }
351: PdfChunk pc = new PdfChunk(returnValue, this );
352: return pc;
353: }
354: currentWidth += font.width(cidChar);
355: if (character == ' ') {
356: lastSpace = currentPosition + 1;
357: lastSpaceWidth = currentWidth;
358: }
359: if (currentWidth > width)
360: break;
361: // if a split-character is encountered, the splitPosition is altered
362: if (splitCharacter.isSplitCharacter(0, currentPosition,
363: length, valueArray, this Chunk))
364: splitPosition = currentPosition + 1;
365: currentPosition++;
366: }
367: } else {
368: while (currentPosition < length) {
369: // the width of every character is added to the currentWidth
370: character = valueArray[currentPosition];
371: // if a newLine or carriageReturn is encountered
372: if (character == '\r' || character == '\n') {
373: newlineSplit = true;
374: int inc = 1;
375: if (character == '\r'
376: && currentPosition + 1 < length
377: && valueArray[currentPosition + 1] == '\n')
378: inc = 2;
379: String returnValue = value
380: .substring(currentPosition + inc);
381: value = value.substring(0, currentPosition);
382: if (value.length() < 1) {
383: value = " ";
384: }
385: PdfChunk pc = new PdfChunk(returnValue, this );
386: return pc;
387: }
388: currentWidth += font.width(character);
389: if (character == ' ') {
390: lastSpace = currentPosition + 1;
391: lastSpaceWidth = currentWidth;
392: }
393: if (currentWidth > width)
394: break;
395: // if a split-character is encountered, the splitPosition is altered
396: if (splitCharacter.isSplitCharacter(0, currentPosition,
397: length, valueArray, null))
398: splitPosition = currentPosition + 1;
399: currentPosition++;
400: }
401: }
402:
403: // if all the characters fit in the total width, null is returned (there is no overflow)
404: if (currentPosition == length) {
405: return null;
406: }
407: // otherwise, the string has to be truncated
408: if (splitPosition < 0) {
409: String returnValue = value;
410: value = "";
411: PdfChunk pc = new PdfChunk(returnValue, this );
412: return pc;
413: }
414: if (lastSpace > splitPosition
415: && splitCharacter.isSplitCharacter(0, 0, 1,
416: singleSpace, null))
417: splitPosition = lastSpace;
418: if (hyphenationEvent != null && lastSpace >= 0
419: && lastSpace < currentPosition) {
420: int wordIdx = getWord(value, lastSpace);
421: if (wordIdx > lastSpace) {
422: String pre = hyphenationEvent.getHyphenatedWordPre(
423: value.substring(lastSpace, wordIdx), font
424: .getFont(), font.size(), width
425: - lastSpaceWidth);
426: String post = hyphenationEvent.getHyphenatedWordPost();
427: if (pre.length() > 0) {
428: String returnValue = post
429: + value.substring(wordIdx);
430: value = trim(value.substring(0, lastSpace) + pre);
431: PdfChunk pc = new PdfChunk(returnValue, this );
432: return pc;
433: }
434: }
435: }
436: String returnValue = value.substring(splitPosition);
437: value = trim(value.substring(0, splitPosition));
438: PdfChunk pc = new PdfChunk(returnValue, this );
439: return pc;
440: }
441:
442: /**
443: * Truncates this <CODE>PdfChunk</CODE> if it's too long for the given width.
444: * <P>
445: * Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated.
446: *
447: * @param width a given width
448: * @return the <CODE>PdfChunk</CODE> that doesn't fit into the width.
449: */
450:
451: PdfChunk truncate(float width) {
452: if (image != null) {
453: if (image.getScaledWidth() > width) {
454: PdfChunk pc = new PdfChunk("", this );
455: value = "";
456: attributes.remove(Chunk.IMAGE);
457: image = null;
458: font = PdfFont.getDefaultFont();
459: return pc;
460: } else
461: return null;
462: }
463:
464: int currentPosition = 0;
465: float currentWidth = 0;
466:
467: // it's no use trying to split if there isn't even enough place for a space
468: if (width < font.width()) {
469: String returnValue = value.substring(1);
470: value = value.substring(0, 1);
471: PdfChunk pc = new PdfChunk(returnValue, this );
472: return pc;
473: }
474:
475: // loop over all the characters of a string
476: // or until the totalWidth is reached
477: int length = value.length();
478: char character;
479: while (currentPosition < length) {
480: // the width of every character is added to the currentWidth
481: character = value.charAt(currentPosition);
482: currentWidth += font.width(character);
483: if (currentWidth > width)
484: break;
485: currentPosition++;
486: }
487:
488: // if all the characters fit in the total width, null is returned (there is no overflow)
489: if (currentPosition == length) {
490: return null;
491: }
492:
493: // otherwise, the string has to be truncated
494: //currentPosition -= 2;
495: // we have to chop off minimum 1 character from the chunk
496: if (currentPosition == 0) {
497: currentPosition = 1;
498: }
499: String returnValue = value.substring(currentPosition);
500: value = value.substring(0, currentPosition);
501: PdfChunk pc = new PdfChunk(returnValue, this );
502: return pc;
503: }
504:
505: // methods to retrieve the membervariables
506:
507: /**
508: * Returns the font of this <CODE>Chunk</CODE>.
509: *
510: * @return a <CODE>PdfFont</CODE>
511: */
512:
513: PdfFont font() {
514: return font;
515: }
516:
517: /**
518: * Returns the color of this <CODE>Chunk</CODE>.
519: *
520: * @return a <CODE>Color</CODE>
521: */
522:
523: Color color() {
524: return (Color) noStroke.get(Chunk.COLOR);
525: }
526:
527: /**
528: * Returns the width of this <CODE>PdfChunk</CODE>.
529: *
530: * @return a width
531: */
532:
533: float width() {
534: return font.width(value);
535: }
536:
537: /**
538: * Checks if the <CODE>PdfChunk</CODE> split was caused by a newline.
539: * @return <CODE>true</CODE> if the <CODE>PdfChunk</CODE> split was caused by a newline.
540: */
541:
542: public boolean isNewlineSplit() {
543: return newlineSplit;
544: }
545:
546: /**
547: * Gets the width of the <CODE>PdfChunk</CODE> taking into account the
548: * extra character and word spacing.
549: * @param charSpacing the extra character spacing
550: * @param wordSpacing the extra word spacing
551: * @return the calculated width
552: */
553:
554: public float getWidthCorrected(float charSpacing, float wordSpacing) {
555: if (image != null) {
556: return image.getScaledWidth() + charSpacing;
557: }
558: int numberOfSpaces = 0;
559: int idx = -1;
560: while ((idx = value.indexOf(' ', idx + 1)) >= 0)
561: ++numberOfSpaces;
562: return width()
563: + (value.length() * charSpacing + numberOfSpaces
564: * wordSpacing);
565: }
566:
567: /**
568: * Gets the text displacement relatiev to the baseline.
569: * @return a displacement in points
570: */
571: public float getTextRise() {
572: Float f = (Float) getAttribute(Chunk.SUBSUPSCRIPT);
573: if (f != null) {
574: return f.floatValue();
575: }
576: return 0.0f;
577: }
578:
579: /**
580: * Trims the last space.
581: * @return the width of the space trimmed, otherwise 0
582: */
583:
584: public float trimLastSpace() {
585: BaseFont ft = font.getFont();
586: if (ft.getFontType() == BaseFont.FONT_TYPE_CJK
587: && ft.getUnicodeEquivalent(' ') != ' ') {
588: if (value.length() > 1 && value.endsWith("\u0001")) {
589: value = value.substring(0, value.length() - 1);
590: return font.width('\u0001');
591: }
592: } else {
593: if (value.length() > 1 && value.endsWith(" ")) {
594: value = value.substring(0, value.length() - 1);
595: return font.width(' ');
596: }
597: }
598: return 0;
599: }
600:
601: public float trimFirstSpace() {
602: BaseFont ft = font.getFont();
603: if (ft.getFontType() == BaseFont.FONT_TYPE_CJK
604: && ft.getUnicodeEquivalent(' ') != ' ') {
605: if (value.length() > 1 && value.startsWith("\u0001")) {
606: value = value.substring(1);
607: return font.width('\u0001');
608: }
609: } else {
610: if (value.length() > 1 && value.startsWith(" ")) {
611: value = value.substring(1);
612: return font.width(' ');
613: }
614: }
615: return 0;
616: }
617:
618: /**
619: * Gets an attribute. The search is made in <CODE>attributes</CODE>
620: * and <CODE>noStroke</CODE>.
621: * @param name the attribute key
622: * @return the attribute value or null if not found
623: */
624:
625: Object getAttribute(String name) {
626: if (attributes.containsKey(name))
627: return attributes.get(name);
628: return noStroke.get(name);
629: }
630:
631: /**
632: *Checks if the attribute exists.
633: * @param name the attribute key
634: * @return <CODE>true</CODE> if the attribute exists
635: */
636:
637: boolean isAttribute(String name) {
638: if (attributes.containsKey(name))
639: return true;
640: return noStroke.containsKey(name);
641: }
642:
643: /**
644: * Checks if this <CODE>PdfChunk</CODE> needs some special metrics handling.
645: * @return <CODE>true</CODE> if this <CODE>PdfChunk</CODE> needs some special metrics handling.
646: */
647:
648: boolean isStroked() {
649: return (!attributes.isEmpty());
650: }
651:
652: /**
653: * Checks if there is an image in the <CODE>PdfChunk</CODE>.
654: * @return <CODE>true</CODE> if an image is present
655: */
656:
657: boolean isImage() {
658: return image != null;
659: }
660:
661: /**
662: * Gets the image in the <CODE>PdfChunk</CODE>.
663: * @return the image or <CODE>null</CODE>
664: */
665:
666: Image getImage() {
667: return image;
668: }
669:
670: /**
671: * Sets the image offset in the x direction
672: * @param offsetX the image offset in the x direction
673: */
674:
675: void setImageOffsetX(float offsetX) {
676: this .offsetX = offsetX;
677: }
678:
679: /**
680: * Gets the image offset in the x direction
681: * @return the image offset in the x direction
682: */
683:
684: float getImageOffsetX() {
685: return offsetX;
686: }
687:
688: /**
689: * Sets the image offset in the y direction
690: * @param offsetY the image offset in the y direction
691: */
692:
693: void setImageOffsetY(float offsetY) {
694: this .offsetY = offsetY;
695: }
696:
697: /**
698: * Gets the image offset in the y direction
699: * @return Gets the image offset in the y direction
700: */
701:
702: float getImageOffsetY() {
703: return offsetY;
704: }
705:
706: /**
707: * sets the value.
708: * @param value content of the Chunk
709: */
710:
711: void setValue(String value) {
712: this .value = value;
713: }
714:
715: /**
716: * @see java.lang.Object#toString()
717: */
718: public String toString() {
719: return value;
720: }
721:
722: /**
723: * Tells you if this string is in Chinese, Japanese, Korean or Identity-H.
724: * @return true if the Chunk has a special encoding
725: */
726:
727: boolean isSpecialEncoding() {
728: return encoding.equals(CJKFont.CJK_ENCODING)
729: || encoding.equals(BaseFont.IDENTITY_H);
730: }
731:
732: /**
733: * Gets the encoding of this string.
734: *
735: * @return a <CODE>String</CODE>
736: */
737:
738: String getEncoding() {
739: return encoding;
740: }
741:
742: int length() {
743: return value.length();
744: }
745:
746: /**
747: * Checks if a character can be used to split a <CODE>PdfString</CODE>.
748: * <P>
749: * for the moment every character less than or equal to SPACE and the character '-' are 'splitCharacters'.
750: *
751: * @param start start position in the array
752: * @param current current position in the array
753: * @param end end position in the array
754: * @param cc the character array that has to be checked
755: * @param ck chunk array
756: * @return <CODE>true</CODE> if the character can be used to split a string, <CODE>false</CODE> otherwise
757: */
758: public boolean isSplitCharacter(int start, int current, int end,
759: char[] cc, PdfChunk[] ck) {
760: char c;
761: if (ck == null)
762: c = cc[current];
763: else
764: c = ck[Math.min(current, ck.length - 1)]
765: .getUnicodeEquivalent(cc[current]);
766: if (c <= ' ' || c == '-') {
767: return true;
768: }
769: if (c < 0x2e80)
770: return false;
771: return ((c >= 0x2e80 && c < 0xd7a0)
772: || (c >= 0xf900 && c < 0xfb00)
773: || (c >= 0xfe30 && c < 0xfe50) || (c >= 0xff61 && c < 0xffa0));
774: }
775:
776: boolean isExtSplitCharacter(int start, int current, int end,
777: char[] cc, PdfChunk[] ck) {
778: return splitCharacter.isSplitCharacter(start, current, end, cc,
779: ck);
780: }
781:
782: /**
783: * Removes all the <VAR>' '</VAR> and <VAR>'-'</VAR>-characters on the right of a <CODE>String</CODE>.
784: * <P>
785: * @param string the <CODE>String<CODE> that has to be trimmed.
786: * @return the trimmed <CODE>String</CODE>
787: */
788: String trim(String string) {
789: BaseFont ft = font.getFont();
790: if (ft.getFontType() == BaseFont.FONT_TYPE_CJK
791: && ft.getUnicodeEquivalent(' ') != ' ') {
792: while (string.endsWith("\u0001")) {
793: string = string.substring(0, string.length() - 1);
794: }
795: } else {
796: while (string.endsWith(" ") || string.endsWith("\t")) {
797: string = string.substring(0, string.length() - 1);
798: }
799: }
800: return string;
801: }
802:
803: public boolean changeLeading() {
804: return changeLeading;
805: }
806:
807: float getCharWidth(char c) {
808: if (noPrint(c))
809: return 0;
810: return font.width(c);
811: }
812:
813: public static boolean noPrint(char c) {
814: return ((c >= 0x200b && c <= 0x200f) || (c >= 0x202a && c <= 0x202e));
815: }
816:
817: }
|