Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (101)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (309)
Collections:
Other Resources:
iText 5 itextpdf.jar Source Code
itextpdf.jar is a component in iText 5 Java library to provide core functionalities. iText Java library allows you to generate and manage PDF documents.
The Source Code files are provided at iText GitHub site.
You can compile it to generate your JAR file, using pom.xml as the build configuration file.
The source code of itextpdf-5.5.14.jar is provided below:
✍: FYIcenter.com
⏎ com/itextpdf/text/pdf/BidiLine.java
/* * * This file is part of the iText (R) project. Copyright (c) 1998-2020 iText Group NV * Authors: Bruno Lowagie, Paulo Soares, et al. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses or write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA, 02110-1301 USA, or download the license from the following URL: * http://itextpdf.com/terms-of-use/ * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * In accordance with Section 7(b) of the GNU Affero General Public License, * a covered work must retain the producer line in every PDF that is created * or manipulated using iText. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the iText software without * disclosing the source code of your own applications. * These activities include: offering paid services to customers as an ASP, * serving PDFs on the fly in a web application, shipping iText with a closed * source product. * * For more information, please contact iText Software Corp. at this * address: sales@itextpdf.com */ package com.itextpdf.text.pdf; import com.itextpdf.text.Chunk; import com.itextpdf.text.Image; import com.itextpdf.text.TabStop; import com.itextpdf.text.Utilities; import com.itextpdf.text.pdf.draw.DrawInterface; import com.itextpdf.text.pdf.draw.LineSeparator; import com.itextpdf.text.pdf.languages.ArabicLigaturizer; import java.util.ArrayList; import java.util.List; /** Does all the line bidirectional processing with PdfChunk assembly. * * @author Paulo Soares */ public class BidiLine { protected int runDirection; protected int pieceSize = 256; protected char text[] = new char[pieceSize]; protected PdfChunk detailChunks[] = new PdfChunk[pieceSize]; protected int totalTextLength = 0; protected byte orderLevels[] = new byte[pieceSize]; protected int indexChars[] = new int[pieceSize]; protected ArrayList<PdfChunk> chunks = new ArrayList<PdfChunk>(); protected int indexChunk = 0; protected int indexChunkChar = 0; protected int currentChar = 0; protected int storedRunDirection; protected char storedText[] = new char[0]; protected PdfChunk storedDetailChunks[] = new PdfChunk[0]; protected int storedTotalTextLength = 0; protected byte storedOrderLevels[] = new byte[0]; protected int storedIndexChars[] = new int[0]; protected int storedIndexChunk = 0; protected int storedIndexChunkChar = 0; protected int storedCurrentChar = 0; protected boolean isWordSplit = false; protected boolean shortStore; // protected ArabicShaping arabic = new ArabicShaping(ArabicShaping.LETTERS_SHAPE | ArabicShaping.LENGTH_GROW_SHRINK | ArabicShaping.TEXT_DIRECTION_LOGICAL); protected static final IntHashtable mirrorChars = new IntHashtable(); protected int arabicOptions; /** Creates new BidiLine */ public BidiLine() { } public BidiLine(BidiLine org) { runDirection = org.runDirection; pieceSize = org.pieceSize; text = org.text.clone(); detailChunks = org.detailChunks.clone(); totalTextLength = org.totalTextLength; orderLevels = org.orderLevels.clone(); indexChars = org.indexChars.clone(); chunks = new ArrayList<PdfChunk>(org.chunks); indexChunk = org.indexChunk; indexChunkChar = org.indexChunkChar; currentChar = org.currentChar; storedRunDirection = org.storedRunDirection; storedText = org.storedText.clone(); storedDetailChunks = org.storedDetailChunks.clone(); storedTotalTextLength = org.storedTotalTextLength; storedOrderLevels = org.storedOrderLevels.clone(); storedIndexChars = org.storedIndexChars.clone(); storedIndexChunk = org.storedIndexChunk; storedIndexChunkChar = org.storedIndexChunkChar; storedCurrentChar = org.storedCurrentChar; shortStore = org.shortStore; arabicOptions = org.arabicOptions; } public boolean isEmpty() { return currentChar >= totalTextLength && indexChunk >= chunks.size(); } public void clearChunks() { chunks.clear(); totalTextLength = 0; currentChar = 0; } public boolean getParagraph(int runDirection) { this.runDirection = runDirection; currentChar = 0; totalTextLength = 0; boolean hasText = false; char c; char uniC; BaseFont bf; for (; indexChunk < chunks.size(); ++indexChunk) { PdfChunk ck = chunks.get(indexChunk); bf = ck.font().getFont(); String s = ck.toString(); int len = s.length(); for (; indexChunkChar < len; ++indexChunkChar) { c = s.charAt(indexChunkChar); uniC = (char)bf.getUnicodeEquivalent(c); if (uniC == '\r' || uniC == '\n') { // next condition is never true for CID if (uniC == '\r' && indexChunkChar + 1 < len && s.charAt(indexChunkChar + 1) == '\n') ++indexChunkChar; ++indexChunkChar; if (indexChunkChar >= len) { indexChunkChar = 0; ++indexChunk; } hasText = true; if (totalTextLength == 0) detailChunks[0] = ck; break; } addPiece(c, ck); } if (hasText) break; indexChunkChar = 0; } if (totalTextLength == 0) return hasText; // remove trailing WS totalTextLength = trimRight(0, totalTextLength - 1) + 1; if (totalTextLength == 0) { return true; } if (runDirection != PdfWriter.RUN_DIRECTION_NO_BIDI) { if (orderLevels.length < totalTextLength) { orderLevels = new byte[pieceSize]; indexChars = new int[pieceSize]; } ArabicLigaturizer.processNumbers(text, 0, totalTextLength, arabicOptions); byte paragraphEmbeddingLevel; switch (runDirection) { case PdfWriter.RUN_DIRECTION_LTR: paragraphEmbeddingLevel = 0; break; case PdfWriter.RUN_DIRECTION_RTL: paragraphEmbeddingLevel = 1; break; case PdfWriter.RUN_DIRECTION_DEFAULT: default: paragraphEmbeddingLevel = -1; break; } BidiOrder order = new BidiOrder(text, 0, totalTextLength, paragraphEmbeddingLevel); byte od[] = order.getLevels(); for (int k = 0; k < totalTextLength; ++k) { orderLevels[k] = od[k]; indexChars[k] = k; } doArabicShapping(); mirrorGlyphs(); } totalTextLength = trimRightEx(0, totalTextLength - 1) + 1; return true; } public void addChunk(PdfChunk chunk) { chunks.add(chunk); } public void addChunks(ArrayList<PdfChunk> chunks) { this.chunks.addAll(chunks); } public void addPiece(char c, PdfChunk chunk) { if (totalTextLength >= pieceSize) { char tempText[] = text; PdfChunk tempDetailChunks[] = detailChunks; pieceSize *= 2; text = new char[pieceSize]; detailChunks = new PdfChunk[pieceSize]; System.arraycopy(tempText, 0, text, 0, totalTextLength); System.arraycopy(tempDetailChunks, 0, detailChunks, 0, totalTextLength); } text[totalTextLength] = c; detailChunks[totalTextLength++] = chunk; } public void save() { if (indexChunk > 0) { if (indexChunk >= chunks.size()) chunks.clear(); else { for (--indexChunk; indexChunk >= 0; --indexChunk) chunks.remove(indexChunk); } indexChunk = 0; } storedRunDirection = runDirection; storedTotalTextLength = totalTextLength; storedIndexChunk = indexChunk; storedIndexChunkChar = indexChunkChar; storedCurrentChar = currentChar; shortStore = currentChar < totalTextLength; if (!shortStore) { // long save if (storedText.length < totalTextLength) { storedText = new char[totalTextLength]; storedDetailChunks = new PdfChunk[totalTextLength]; } System.arraycopy(text, 0, storedText, 0, totalTextLength); System.arraycopy(detailChunks, 0, storedDetailChunks, 0, totalTextLength); } if (runDirection != PdfWriter.RUN_DIRECTION_NO_BIDI) { if (storedOrderLevels.length < totalTextLength) { storedOrderLevels = new byte[totalTextLength]; storedIndexChars = new int[totalTextLength]; } System.arraycopy(orderLevels, currentChar, storedOrderLevels, currentChar, totalTextLength - currentChar); System.arraycopy(indexChars, currentChar, storedIndexChars, currentChar, totalTextLength - currentChar); } } public void restore() { runDirection = storedRunDirection; totalTextLength = storedTotalTextLength; indexChunk = storedIndexChunk; indexChunkChar = storedIndexChunkChar; currentChar = storedCurrentChar; if (!shortStore) { // long restore System.arraycopy(storedText, 0, text, 0, totalTextLength); System.arraycopy(storedDetailChunks, 0, detailChunks, 0, totalTextLength); } if (runDirection != PdfWriter.RUN_DIRECTION_NO_BIDI) { System.arraycopy(storedOrderLevels, currentChar, orderLevels, currentChar, totalTextLength - currentChar); System.arraycopy(storedIndexChars, currentChar, indexChars, currentChar, totalTextLength - currentChar); } } public void mirrorGlyphs() { for (int k = 0; k < totalTextLength; ++k) { if ((orderLevels[k] & 1) == 1) { int mirror = mirrorChars.get(text[k]); if (mirror != 0) text[k] = (char)mirror; } } } public void doArabicShapping() { int src = 0; int dest = 0; for (;;) { while (src < totalTextLength) { char c = text[src]; if (c >= 0x0600 && c <= 0x06ff) break; if (src != dest) { text[dest] = text[src]; detailChunks[dest] = detailChunks[src]; orderLevels[dest] = orderLevels[src]; } ++src; ++dest; } if (src >= totalTextLength) { totalTextLength = dest; return; } int startArabicIdx = src; ++src; while (src < totalTextLength) { char c = text[src]; if (c < 0x0600 || c > 0x06ff) break; ++src; } int arabicWordSize = src - startArabicIdx; int size = ArabicLigaturizer.arabic_shape(text, startArabicIdx, arabicWordSize, text, dest, arabicWordSize, arabicOptions); if (startArabicIdx != dest) { for (int k = 0; k < size; ++k) { detailChunks[dest] = detailChunks[startArabicIdx]; orderLevels[dest++] = orderLevels[startArabicIdx++]; } } else dest += size; } } public PdfLine processLine(float leftX, float width, int alignment, int runDirection, int arabicOptions, float minY, float yLine, float descender) { isWordSplit = false; this.arabicOptions = arabicOptions; save(); boolean isRTL = runDirection == PdfWriter.RUN_DIRECTION_RTL; if (currentChar >= totalTextLength) { boolean hasText = getParagraph(runDirection); if (!hasText) return null; if (totalTextLength == 0) { ArrayList<PdfChunk> ar = new ArrayList<PdfChunk>(); PdfChunk ck = new PdfChunk("", detailChunks[0]); ar.add(ck); return new PdfLine(0, 0, width, alignment, true, ar, isRTL); } } float originalWidth = width; int lastSplit = -1; if (currentChar != 0) currentChar = trimLeftEx(currentChar, totalTextLength - 1); int oldCurrentChar = currentChar; int uniC = 0; PdfChunk ck = null; float charWidth = 0; PdfChunk lastValidChunk = null; TabStop tabStop = null; List<TabStop> rtlTabsToBeAligned = new ArrayList<TabStop>(); float tabStopAnchorPosition = Float.NaN; float tabPosition = Float.NaN; boolean surrogate = false; for (; currentChar < totalTextLength; ++currentChar) { ck = detailChunks[currentChar]; if (ck.isImage() && minY < yLine) { Image img = ck.getImage(); if (img.isScaleToFitHeight() && yLine + 2 * descender - img.getScaledHeight() - ck.getImageOffsetY() - img.getSpacingBefore() < minY) { float scalePercent = (yLine + 2 * descender - ck.getImageOffsetY() - img.getSpacingBefore() - minY) / img.getScaledHeight(); ck.setImageScalePercentage(scalePercent); } } surrogate = Utilities.isSurrogatePair(text, currentChar); if (surrogate) uniC = ck.getUnicodeEquivalent(Utilities.convertToUtf32(text, currentChar)); else uniC = ck.getUnicodeEquivalent(text[currentChar]); if (PdfChunk.noPrint(uniC)) continue; if (surrogate) charWidth = ck.getCharWidth(uniC); else { if (ck.isImage()) { charWidth = ck.getImageWidth(); } else { charWidth = ck.getCharWidth(text[currentChar]); } } if (width - charWidth < 0) { // If the chunk is an image and it is the first one in line, check if resize requested // If so, resize to fit the current line width if (lastValidChunk == null && ck.isImage()) { Image img = ck.getImage(); if (img.isScaleToFitLineWhenOverflow()) { //float scalePercent = width / img.getWidth() * 100; //img.scalePercent(scalePercent); float scalePercent = width / img.getWidth(); ck.setImageScalePercentage(scalePercent); charWidth = width; } } } if (ck.isTab()) { if (ck.isAttribute(Chunk.TABSETTINGS)) { lastSplit = currentChar; if (tabStop != null) { width = processTabStop(tabStop, tabPosition, originalWidth, width, tabStopAnchorPosition, isRTL, rtlTabsToBeAligned); } tabStop = PdfChunk.getTabStop(ck, originalWidth - width); if (tabStop.getPosition() > originalWidth) { tabStop = null; break; } ck.setTabStop(tabStop); if (!isRTL && tabStop.getAlignment() == TabStop.Alignment.LEFT) { width = originalWidth - tabStop.getPosition(); tabStop = null; tabPosition = Float.NaN; tabStopAnchorPosition = Float.NaN; } else { tabPosition = originalWidth - width; tabStopAnchorPosition = Float.NaN; } } else { Object[] tab = (Object[])ck.getAttribute(Chunk.TAB); //Keep deprecated tab logic for backward compatibility... float tabStopPosition = ((Float)tab[1]).floatValue(); boolean newLine = ((Boolean)tab[2]).booleanValue(); if (newLine && tabStopPosition < originalWidth - width) { return new PdfLine(0, originalWidth, width, alignment, true, createArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); } detailChunks[currentChar].adjustLeft(leftX); width = originalWidth - tabStopPosition; } } else if (ck.isSeparator()) { Object[] sep = (Object[])ck.getAttribute(Chunk.SEPARATOR); DrawInterface di = (DrawInterface)sep[0]; Boolean vertical = (Boolean)sep[1]; if (vertical && di instanceof LineSeparator) { float separatorWidth = originalWidth * ((LineSeparator) di).getPercentage() / 100f; width -= separatorWidth; if (width < 0) { width = 0; } } } else { boolean splitChar = ck.isExtSplitCharacter(oldCurrentChar, currentChar, totalTextLength, text, detailChunks); if (splitChar && Character.isWhitespace((char)uniC)) lastSplit = currentChar; if (width - charWidth < 0) break; if (tabStop != null && tabStop.getAlignment() == TabStop.Alignment.ANCHOR && Float.isNaN(tabStopAnchorPosition) && tabStop.getAnchorChar() == (char) uniC) { tabStopAnchorPosition = originalWidth - width; } width -= charWidth; if (splitChar) lastSplit = currentChar; } lastValidChunk = ck; if (surrogate) ++currentChar; } if (lastValidChunk == null) { // not even a single char fit; must output the first char ++currentChar; if (surrogate) ++currentChar; return new PdfLine(0, originalWidth, 0, alignment, false, createArrayOfPdfChunks(currentChar - 1, currentChar - 1), isRTL); } if (tabStop != null) { width = processTabStop(tabStop, tabPosition, originalWidth, width, tabStopAnchorPosition, isRTL, rtlTabsToBeAligned); } if (rtlTabsToBeAligned != null) { for (TabStop rtlTabStop : rtlTabsToBeAligned) { rtlTabStop.setPosition(originalWidth - width - rtlTabStop.getPosition()); } } if (currentChar >= totalTextLength) { // there was more line than text return new PdfLine(0, originalWidth, width, alignment, true, createArrayOfPdfChunks(oldCurrentChar, totalTextLength - 1), isRTL); } int newCurrentChar = trimRightEx(oldCurrentChar, currentChar - 1); if (newCurrentChar < oldCurrentChar) { // only WS return new PdfLine(0, originalWidth, width, alignment, false, createArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); } if (newCurrentChar == currentChar - 1) { // middle of word HyphenationEvent he = (HyphenationEvent)lastValidChunk.getAttribute(Chunk.HYPHENATION); if (he != null) { int word[] = getWord(oldCurrentChar, newCurrentChar); if (word != null) { float testWidth = width + getWidth(word[0], currentChar - 1); String pre = he.getHyphenatedWordPre(new String(text, word[0], word[1] - word[0]), lastValidChunk.font().getFont(), lastValidChunk.font().size(), testWidth); String post = he.getHyphenatedWordPost(); if (pre.length() > 0) { PdfChunk extra = new PdfChunk(pre, lastValidChunk); currentChar = word[1] - post.length(); return new PdfLine(0, originalWidth, testWidth - lastValidChunk.width(pre), alignment, false, createArrayOfPdfChunks(oldCurrentChar, word[0] - 1, extra), isRTL); } } } } if (lastSplit == -1) isWordSplit = true; if (lastSplit == -1 || lastSplit >= newCurrentChar) { // no split point or split point ahead of end return new PdfLine(0, originalWidth, width + getWidth(newCurrentChar + 1, currentChar - 1, originalWidth), alignment, false, createArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); } // standard split currentChar = lastSplit + 1; newCurrentChar = trimRightEx(oldCurrentChar, lastSplit); if (newCurrentChar < oldCurrentChar) { // only WS again newCurrentChar = currentChar - 1; } return new PdfLine(0, originalWidth, originalWidth - getWidth(oldCurrentChar, newCurrentChar, originalWidth), alignment, false, createArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); } private float processTabStop(TabStop tabStop, float tabPosition, float originalWidth, float width, float tabStopAnchorPosition, boolean isRTL, List<TabStop> rtlTabsToBeAligned) { float tabStopPosition = tabStop.getPosition(tabPosition, originalWidth - width, tabStopAnchorPosition); width -= tabStopPosition - tabPosition; if (width < 0) { tabStopPosition += width; width = 0; } if (!isRTL) { tabStop.setPosition(tabStopPosition); } else { tabStop.setPosition(tabPosition); // This will be mirrored when we know exact line width rtlTabsToBeAligned.add(tabStop); } return width; } /** * Call this after processLine() to know if any word was split into several lines. * @return */ public boolean isWordSplit() { return isWordSplit; } /** Gets the width of a range of characters. * @param startIdx the first index to calculate * @param lastIdx the last inclusive index to calculate * @return the sum of all widths */ public float getWidth(int startIdx, int lastIdx) { return getWidth(startIdx, lastIdx, 0); } /** Gets the width of a range of characters. * @param startIdx the first index to calculate * @param lastIdx the last inclusive index to calculate * @param originalWidth the full width of the line. It is used in case of RTL and tab stops * @return the sum of all widths */ public float getWidth(int startIdx, int lastIdx, float originalWidth) { char c = 0; PdfChunk ck = null; float width = 0; TabStop tabStop = null; float tabStopAnchorPosition = Float.NaN; float tabPosition = Float.NaN; for (; startIdx <= lastIdx; ++startIdx) { boolean surrogate = Utilities.isSurrogatePair(text, startIdx); if (detailChunks[startIdx].isTab() //Keep deprecated tab logic for backward compatibility... && detailChunks[startIdx].isAttribute(Chunk.TABSETTINGS)) { if (tabStop != null) { float tabStopPosition = tabStop.getPosition(tabPosition, width, tabStopAnchorPosition); width = tabStopPosition + (width - tabPosition); tabStop.setPosition(tabStopPosition); } tabStop = detailChunks[startIdx].getTabStop(); if (tabStop == null) { tabStop = PdfChunk.getTabStop(detailChunks[startIdx], width); tabPosition = width; tabStopAnchorPosition = Float.NaN; } else { if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { width = originalWidth - tabStop.getPosition(); } else { width = tabStop.getPosition(); } tabStop = null; tabPosition = Float.NaN; tabStopAnchorPosition = Float.NaN; } } else if (surrogate) { width += detailChunks[startIdx].getCharWidth(Utilities.convertToUtf32(text, startIdx)); ++startIdx; } else { c = text[startIdx]; ck = detailChunks[startIdx]; if (PdfChunk.noPrint(ck.getUnicodeEquivalent(c))) continue; if (tabStop != null && tabStop.getAlignment() != TabStop.Alignment.ANCHOR && Float.isNaN(tabStopAnchorPosition) && tabStop.getAnchorChar() == (char)ck.getUnicodeEquivalent(c)) { tabStopAnchorPosition = width; } width += detailChunks[startIdx].getCharWidth(c); } } if (tabStop != null) { float tabStopPosition = tabStop.getPosition(tabPosition, width, tabStopAnchorPosition); width = tabStopPosition + (width - tabPosition); tabStop.setPosition(tabStopPosition); } return width; } public ArrayList<PdfChunk> createArrayOfPdfChunks(int startIdx, int endIdx) { return createArrayOfPdfChunks(startIdx, endIdx, null); } public ArrayList<PdfChunk> createArrayOfPdfChunks(int startIdx, int endIdx, PdfChunk extraPdfChunk) { boolean bidi = runDirection != PdfWriter.RUN_DIRECTION_NO_BIDI; if (bidi) reorder(startIdx, endIdx); ArrayList<PdfChunk> ar = new ArrayList<PdfChunk>(); PdfChunk refCk = detailChunks[startIdx]; PdfChunk ck = null; StringBuffer buf = new StringBuffer(); char c; int idx = 0; for (; startIdx <= endIdx; ++startIdx) { idx = bidi ? indexChars[startIdx] : startIdx; c = text[idx]; ck = detailChunks[idx]; if (PdfChunk.noPrint(ck.getUnicodeEquivalent(c))) continue; if (ck.isImage() || ck.isSeparator() || ck.isTab()) { if (buf.length() > 0) { ar.add(new PdfChunk(buf.toString(), refCk)); buf = new StringBuffer(); } ar.add(ck); } else if (ck == refCk) { buf.append(c); } else { if (buf.length() > 0) { ar.add(new PdfChunk(buf.toString(), refCk)); buf = new StringBuffer(); } if (!ck.isImage() && !ck.isSeparator() && !ck.isTab()) buf.append(c); refCk = ck; } } if (buf.length() > 0) { ar.add(new PdfChunk(buf.toString(), refCk)); } if (extraPdfChunk != null) ar.add(extraPdfChunk); return ar; } public int[] getWord(int startIdx, int idx) { int last = idx; int first = idx; // forward for (; last < totalTextLength; ++last) { if (!Character.isLetter(text[last]) && !Character.isDigit(text[last]) && text[last] != '\u00AD') break; } if (last == idx) return null; // backward for (; first >= startIdx; --first) { if (!Character.isLetter(text[first]) && !Character.isDigit(text[first]) && text[first] != '\u00AD') break; } ++first; return new int[]{first, last}; } public int trimRight(int startIdx, int endIdx) { int idx = endIdx; char c; for (; idx >= startIdx; --idx) { c = (char)detailChunks[idx].getUnicodeEquivalent(text[idx]); if (!isWS(c)) break; } return idx; } public int trimLeft(int startIdx, int endIdx) { int idx = startIdx; char c; for (; idx <= endIdx; ++idx) { c = (char)detailChunks[idx].getUnicodeEquivalent(text[idx]); if (!isWS(c)) break; } return idx; } public int trimRightEx(int startIdx, int endIdx) { int idx = endIdx; char c = 0; for (; idx >= startIdx; --idx) { c = (char)detailChunks[idx].getUnicodeEquivalent(text[idx]); if (!isWS(c) && !PdfChunk.noPrint(c)) { if (detailChunks[idx].isTab() //Keep deprecated tab logic for backward compatibility... && detailChunks[idx].isAttribute(Chunk.TABSETTINGS)) { Object[] tab = (Object[])detailChunks[idx].getAttribute(Chunk.TAB); boolean isWhitespace = (Boolean)tab[1]; if (isWhitespace) continue; } break; } } return idx; } public int trimLeftEx(int startIdx, int endIdx) { int idx = startIdx; char c = 0; for (; idx <= endIdx; ++idx) { c = (char)detailChunks[idx].getUnicodeEquivalent(text[idx]); if (!isWS(c) && !PdfChunk.noPrint(c)) { if (detailChunks[idx].isTab() //Keep deprecated tab logic for backward compatibility... && detailChunks[idx].isAttribute(Chunk.TABSETTINGS)) { Object[] tab = (Object[])detailChunks[idx].getAttribute(Chunk.TAB); boolean isWhitespace = (Boolean)tab[1]; if (isWhitespace) continue; } break; } } return idx; } public void reorder(int start, int end) { byte maxLevel = orderLevels[start]; byte minLevel = maxLevel; byte onlyOddLevels = maxLevel; byte onlyEvenLevels = maxLevel; for (int k = start + 1; k <= end; ++k) { byte b = orderLevels[k]; if (b > maxLevel) maxLevel = b; else if (b < minLevel) minLevel = b; onlyOddLevels &= b; onlyEvenLevels |= b; } if ((onlyEvenLevels & 1) == 0) // nothing to do return; if ((onlyOddLevels & 1) == 1) { // single inversion flip(start, end + 1); return; } minLevel |= 1; for (; maxLevel >= minLevel; --maxLevel) { int pstart = start; for (;;) { for (;pstart <= end; ++pstart) { if (orderLevels[pstart] >= maxLevel) break; } if (pstart > end) break; int pend = pstart + 1; for (; pend <= end; ++pend) { if (orderLevels[pend] < maxLevel) break; } flip(pstart, pend); pstart = pend + 1; } } } public void flip(int start, int end) { int mid = (start + end) / 2; --end; for (; start < mid; ++start, --end) { int temp = indexChars[start]; indexChars[start] = indexChars[end]; indexChars[end] = temp; } } public static boolean isWS(char c) { return c <= ' '; } static { mirrorChars.put(0x0028, 0x0029); // LEFT PARENTHESIS mirrorChars.put(0x0029, 0x0028); // RIGHT PARENTHESIS mirrorChars.put(0x003C, 0x003E); // LESS-THAN SIGN mirrorChars.put(0x003E, 0x003C); // GREATER-THAN SIGN mirrorChars.put(0x005B, 0x005D); // LEFT SQUARE BRACKET mirrorChars.put(0x005D, 0x005B); // RIGHT SQUARE BRACKET mirrorChars.put(0x007B, 0x007D); // LEFT CURLY BRACKET mirrorChars.put(0x007D, 0x007B); // RIGHT CURLY BRACKET mirrorChars.put(0x00AB, 0x00BB); // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK mirrorChars.put(0x00BB, 0x00AB); // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK mirrorChars.put(0x2039, 0x203A); // SINGLE LEFT-POINTING ANGLE QUOTATION MARK mirrorChars.put(0x203A, 0x2039); // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK mirrorChars.put(0x2045, 0x2046); // LEFT SQUARE BRACKET WITH QUILL mirrorChars.put(0x2046, 0x2045); // RIGHT SQUARE BRACKET WITH QUILL mirrorChars.put(0x207D, 0x207E); // SUPERSCRIPT LEFT PARENTHESIS mirrorChars.put(0x207E, 0x207D); // SUPERSCRIPT RIGHT PARENTHESIS mirrorChars.put(0x208D, 0x208E); // SUBSCRIPT LEFT PARENTHESIS mirrorChars.put(0x208E, 0x208D); // SUBSCRIPT RIGHT PARENTHESIS mirrorChars.put(0x2208, 0x220B); // ELEMENT OF mirrorChars.put(0x2209, 0x220C); // NOT AN ELEMENT OF mirrorChars.put(0x220A, 0x220D); // SMALL ELEMENT OF mirrorChars.put(0x220B, 0x2208); // CONTAINS AS MEMBER mirrorChars.put(0x220C, 0x2209); // DOES NOT CONTAIN AS MEMBER mirrorChars.put(0x220D, 0x220A); // SMALL CONTAINS AS MEMBER mirrorChars.put(0x2215, 0x29F5); // DIVISION SLASH mirrorChars.put(0x223C, 0x223D); // TILDE OPERATOR mirrorChars.put(0x223D, 0x223C); // REVERSED TILDE mirrorChars.put(0x2243, 0x22CD); // ASYMPTOTICALLY EQUAL TO mirrorChars.put(0x2252, 0x2253); // APPROXIMATELY EQUAL TO OR THE IMAGE OF mirrorChars.put(0x2253, 0x2252); // IMAGE OF OR APPROXIMATELY EQUAL TO mirrorChars.put(0x2254, 0x2255); // COLON EQUALS mirrorChars.put(0x2255, 0x2254); // EQUALS COLON mirrorChars.put(0x2264, 0x2265); // LESS-THAN OR EQUAL TO mirrorChars.put(0x2265, 0x2264); // GREATER-THAN OR EQUAL TO mirrorChars.put(0x2266, 0x2267); // LESS-THAN OVER EQUAL TO mirrorChars.put(0x2267, 0x2266); // GREATER-THAN OVER EQUAL TO mirrorChars.put(0x2268, 0x2269); // [BEST FIT] LESS-THAN BUT NOT EQUAL TO mirrorChars.put(0x2269, 0x2268); // [BEST FIT] GREATER-THAN BUT NOT EQUAL TO mirrorChars.put(0x226A, 0x226B); // MUCH LESS-THAN mirrorChars.put(0x226B, 0x226A); // MUCH GREATER-THAN mirrorChars.put(0x226E, 0x226F); // [BEST FIT] NOT LESS-THAN mirrorChars.put(0x226F, 0x226E); // [BEST FIT] NOT GREATER-THAN mirrorChars.put(0x2270, 0x2271); // [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO mirrorChars.put(0x2271, 0x2270); // [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO mirrorChars.put(0x2272, 0x2273); // [BEST FIT] LESS-THAN OR EQUIVALENT TO mirrorChars.put(0x2273, 0x2272); // [BEST FIT] GREATER-THAN OR EQUIVALENT TO mirrorChars.put(0x2274, 0x2275); // [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO mirrorChars.put(0x2275, 0x2274); // [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO mirrorChars.put(0x2276, 0x2277); // LESS-THAN OR GREATER-THAN mirrorChars.put(0x2277, 0x2276); // GREATER-THAN OR LESS-THAN mirrorChars.put(0x2278, 0x2279); // NEITHER LESS-THAN NOR GREATER-THAN mirrorChars.put(0x2279, 0x2278); // NEITHER GREATER-THAN NOR LESS-THAN mirrorChars.put(0x227A, 0x227B); // PRECEDES mirrorChars.put(0x227B, 0x227A); // SUCCEEDS mirrorChars.put(0x227C, 0x227D); // PRECEDES OR EQUAL TO mirrorChars.put(0x227D, 0x227C); // SUCCEEDS OR EQUAL TO mirrorChars.put(0x227E, 0x227F); // [BEST FIT] PRECEDES OR EQUIVALENT TO mirrorChars.put(0x227F, 0x227E); // [BEST FIT] SUCCEEDS OR EQUIVALENT TO mirrorChars.put(0x2280, 0x2281); // [BEST FIT] DOES NOT PRECEDE mirrorChars.put(0x2281, 0x2280); // [BEST FIT] DOES NOT SUCCEED mirrorChars.put(0x2282, 0x2283); // SUBSET OF mirrorChars.put(0x2283, 0x2282); // SUPERSET OF mirrorChars.put(0x2284, 0x2285); // [BEST FIT] NOT A SUBSET OF mirrorChars.put(0x2285, 0x2284); // [BEST FIT] NOT A SUPERSET OF mirrorChars.put(0x2286, 0x2287); // SUBSET OF OR EQUAL TO mirrorChars.put(0x2287, 0x2286); // SUPERSET OF OR EQUAL TO mirrorChars.put(0x2288, 0x2289); // [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO mirrorChars.put(0x2289, 0x2288); // [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO mirrorChars.put(0x228A, 0x228B); // [BEST FIT] SUBSET OF WITH NOT EQUAL TO mirrorChars.put(0x228B, 0x228A); // [BEST FIT] SUPERSET OF WITH NOT EQUAL TO mirrorChars.put(0x228F, 0x2290); // SQUARE IMAGE OF mirrorChars.put(0x2290, 0x228F); // SQUARE ORIGINAL OF mirrorChars.put(0x2291, 0x2292); // SQUARE IMAGE OF OR EQUAL TO mirrorChars.put(0x2292, 0x2291); // SQUARE ORIGINAL OF OR EQUAL TO mirrorChars.put(0x2298, 0x29B8); // CIRCLED DIVISION SLASH mirrorChars.put(0x22A2, 0x22A3); // RIGHT TACK mirrorChars.put(0x22A3, 0x22A2); // LEFT TACK mirrorChars.put(0x22A6, 0x2ADE); // ASSERTION mirrorChars.put(0x22A8, 0x2AE4); // TRUE mirrorChars.put(0x22A9, 0x2AE3); // FORCES mirrorChars.put(0x22AB, 0x2AE5); // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE mirrorChars.put(0x22B0, 0x22B1); // PRECEDES UNDER RELATION mirrorChars.put(0x22B1, 0x22B0); // SUCCEEDS UNDER RELATION mirrorChars.put(0x22B2, 0x22B3); // NORMAL SUBGROUP OF mirrorChars.put(0x22B3, 0x22B2); // CONTAINS AS NORMAL SUBGROUP mirrorChars.put(0x22B4, 0x22B5); // NORMAL SUBGROUP OF OR EQUAL TO mirrorChars.put(0x22B5, 0x22B4); // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO mirrorChars.put(0x22B6, 0x22B7); // ORIGINAL OF mirrorChars.put(0x22B7, 0x22B6); // IMAGE OF mirrorChars.put(0x22C9, 0x22CA); // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT mirrorChars.put(0x22CA, 0x22C9); // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT mirrorChars.put(0x22CB, 0x22CC); // LEFT SEMIDIRECT PRODUCT mirrorChars.put(0x22CC, 0x22CB); // RIGHT SEMIDIRECT PRODUCT mirrorChars.put(0x22CD, 0x2243); // REVERSED TILDE EQUALS mirrorChars.put(0x22D0, 0x22D1); // DOUBLE SUBSET mirrorChars.put(0x22D1, 0x22D0); // DOUBLE SUPERSET mirrorChars.put(0x22D6, 0x22D7); // LESS-THAN WITH DOT mirrorChars.put(0x22D7, 0x22D6); // GREATER-THAN WITH DOT mirrorChars.put(0x22D8, 0x22D9); // VERY MUCH LESS-THAN mirrorChars.put(0x22D9, 0x22D8); // VERY MUCH GREATER-THAN mirrorChars.put(0x22DA, 0x22DB); // LESS-THAN EQUAL TO OR GREATER-THAN mirrorChars.put(0x22DB, 0x22DA); // GREATER-THAN EQUAL TO OR LESS-THAN mirrorChars.put(0x22DC, 0x22DD); // EQUAL TO OR LESS-THAN mirrorChars.put(0x22DD, 0x22DC); // EQUAL TO OR GREATER-THAN mirrorChars.put(0x22DE, 0x22DF); // EQUAL TO OR PRECEDES mirrorChars.put(0x22DF, 0x22DE); // EQUAL TO OR SUCCEEDS mirrorChars.put(0x22E0, 0x22E1); // [BEST FIT] DOES NOT PRECEDE OR EQUAL mirrorChars.put(0x22E1, 0x22E0); // [BEST FIT] DOES NOT SUCCEED OR EQUAL mirrorChars.put(0x22E2, 0x22E3); // [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO mirrorChars.put(0x22E3, 0x22E2); // [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO mirrorChars.put(0x22E4, 0x22E5); // [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO mirrorChars.put(0x22E5, 0x22E4); // [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO mirrorChars.put(0x22E6, 0x22E7); // [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO mirrorChars.put(0x22E7, 0x22E6); // [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO mirrorChars.put(0x22E8, 0x22E9); // [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO mirrorChars.put(0x22E9, 0x22E8); // [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO mirrorChars.put(0x22EA, 0x22EB); // [BEST FIT] NOT NORMAL SUBGROUP OF mirrorChars.put(0x22EB, 0x22EA); // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP mirrorChars.put(0x22EC, 0x22ED); // [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO mirrorChars.put(0x22ED, 0x22EC); // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL mirrorChars.put(0x22F0, 0x22F1); // UP RIGHT DIAGONAL ELLIPSIS mirrorChars.put(0x22F1, 0x22F0); // DOWN RIGHT DIAGONAL ELLIPSIS mirrorChars.put(0x22F2, 0x22FA); // ELEMENT OF WITH LONG HORIZONTAL STROKE mirrorChars.put(0x22F3, 0x22FB); // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE mirrorChars.put(0x22F4, 0x22FC); // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE mirrorChars.put(0x22F6, 0x22FD); // ELEMENT OF WITH OVERBAR mirrorChars.put(0x22F7, 0x22FE); // SMALL ELEMENT OF WITH OVERBAR mirrorChars.put(0x22FA, 0x22F2); // CONTAINS WITH LONG HORIZONTAL STROKE mirrorChars.put(0x22FB, 0x22F3); // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE mirrorChars.put(0x22FC, 0x22F4); // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE mirrorChars.put(0x22FD, 0x22F6); // CONTAINS WITH OVERBAR mirrorChars.put(0x22FE, 0x22F7); // SMALL CONTAINS WITH OVERBAR mirrorChars.put(0x2308, 0x2309); // LEFT CEILING mirrorChars.put(0x2309, 0x2308); // RIGHT CEILING mirrorChars.put(0x230A, 0x230B); // LEFT FLOOR mirrorChars.put(0x230B, 0x230A); // RIGHT FLOOR mirrorChars.put(0x2329, 0x232A); // LEFT-POINTING ANGLE BRACKET mirrorChars.put(0x232A, 0x2329); // RIGHT-POINTING ANGLE BRACKET mirrorChars.put(0x2768, 0x2769); // MEDIUM LEFT PARENTHESIS ORNAMENT mirrorChars.put(0x2769, 0x2768); // MEDIUM RIGHT PARENTHESIS ORNAMENT mirrorChars.put(0x276A, 0x276B); // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT mirrorChars.put(0x276B, 0x276A); // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT mirrorChars.put(0x276C, 0x276D); // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT mirrorChars.put(0x276D, 0x276C); // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT mirrorChars.put(0x276E, 0x276F); // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT mirrorChars.put(0x276F, 0x276E); // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT mirrorChars.put(0x2770, 0x2771); // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT mirrorChars.put(0x2771, 0x2770); // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT mirrorChars.put(0x2772, 0x2773); // LIGHT LEFT TORTOISE SHELL BRACKET mirrorChars.put(0x2773, 0x2772); // LIGHT RIGHT TORTOISE SHELL BRACKET mirrorChars.put(0x2774, 0x2775); // MEDIUM LEFT CURLY BRACKET ORNAMENT mirrorChars.put(0x2775, 0x2774); // MEDIUM RIGHT CURLY BRACKET ORNAMENT mirrorChars.put(0x27D5, 0x27D6); // LEFT OUTER JOIN mirrorChars.put(0x27D6, 0x27D5); // RIGHT OUTER JOIN mirrorChars.put(0x27DD, 0x27DE); // LONG RIGHT TACK mirrorChars.put(0x27DE, 0x27DD); // LONG LEFT TACK mirrorChars.put(0x27E2, 0x27E3); // WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK mirrorChars.put(0x27E3, 0x27E2); // WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK mirrorChars.put(0x27E4, 0x27E5); // WHITE SQUARE WITH LEFTWARDS TICK mirrorChars.put(0x27E5, 0x27E4); // WHITE SQUARE WITH RIGHTWARDS TICK mirrorChars.put(0x27E6, 0x27E7); // MATHEMATICAL LEFT WHITE SQUARE BRACKET mirrorChars.put(0x27E7, 0x27E6); // MATHEMATICAL RIGHT WHITE SQUARE BRACKET mirrorChars.put(0x27E8, 0x27E9); // MATHEMATICAL LEFT ANGLE BRACKET mirrorChars.put(0x27E9, 0x27E8); // MATHEMATICAL RIGHT ANGLE BRACKET mirrorChars.put(0x27EA, 0x27EB); // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET mirrorChars.put(0x27EB, 0x27EA); // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET mirrorChars.put(0x2983, 0x2984); // LEFT WHITE CURLY BRACKET mirrorChars.put(0x2984, 0x2983); // RIGHT WHITE CURLY BRACKET mirrorChars.put(0x2985, 0x2986); // LEFT WHITE PARENTHESIS mirrorChars.put(0x2986, 0x2985); // RIGHT WHITE PARENTHESIS mirrorChars.put(0x2987, 0x2988); // Z NOTATION LEFT IMAGE BRACKET mirrorChars.put(0x2988, 0x2987); // Z NOTATION RIGHT IMAGE BRACKET mirrorChars.put(0x2989, 0x298A); // Z NOTATION LEFT BINDING BRACKET mirrorChars.put(0x298A, 0x2989); // Z NOTATION RIGHT BINDING BRACKET mirrorChars.put(0x298B, 0x298C); // LEFT SQUARE BRACKET WITH UNDERBAR mirrorChars.put(0x298C, 0x298B); // RIGHT SQUARE BRACKET WITH UNDERBAR mirrorChars.put(0x298D, 0x2990); // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER mirrorChars.put(0x298E, 0x298F); // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER mirrorChars.put(0x298F, 0x298E); // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER mirrorChars.put(0x2990, 0x298D); // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER mirrorChars.put(0x2991, 0x2992); // LEFT ANGLE BRACKET WITH DOT mirrorChars.put(0x2992, 0x2991); // RIGHT ANGLE BRACKET WITH DOT mirrorChars.put(0x2993, 0x2994); // LEFT ARC LESS-THAN BRACKET mirrorChars.put(0x2994, 0x2993); // RIGHT ARC GREATER-THAN BRACKET mirrorChars.put(0x2995, 0x2996); // DOUBLE LEFT ARC GREATER-THAN BRACKET mirrorChars.put(0x2996, 0x2995); // DOUBLE RIGHT ARC LESS-THAN BRACKET mirrorChars.put(0x2997, 0x2998); // LEFT BLACK TORTOISE SHELL BRACKET mirrorChars.put(0x2998, 0x2997); // RIGHT BLACK TORTOISE SHELL BRACKET mirrorChars.put(0x29B8, 0x2298); // CIRCLED REVERSE SOLIDUS mirrorChars.put(0x29C0, 0x29C1); // CIRCLED LESS-THAN mirrorChars.put(0x29C1, 0x29C0); // CIRCLED GREATER-THAN mirrorChars.put(0x29C4, 0x29C5); // SQUARED RISING DIAGONAL SLASH mirrorChars.put(0x29C5, 0x29C4); // SQUARED FALLING DIAGONAL SLASH mirrorChars.put(0x29CF, 0x29D0); // LEFT TRIANGLE BESIDE VERTICAL BAR mirrorChars.put(0x29D0, 0x29CF); // VERTICAL BAR BESIDE RIGHT TRIANGLE mirrorChars.put(0x29D1, 0x29D2); // BOWTIE WITH LEFT HALF BLACK mirrorChars.put(0x29D2, 0x29D1); // BOWTIE WITH RIGHT HALF BLACK mirrorChars.put(0x29D4, 0x29D5); // TIMES WITH LEFT HALF BLACK mirrorChars.put(0x29D5, 0x29D4); // TIMES WITH RIGHT HALF BLACK mirrorChars.put(0x29D8, 0x29D9); // LEFT WIGGLY FENCE mirrorChars.put(0x29D9, 0x29D8); // RIGHT WIGGLY FENCE mirrorChars.put(0x29DA, 0x29DB); // LEFT DOUBLE WIGGLY FENCE mirrorChars.put(0x29DB, 0x29DA); // RIGHT DOUBLE WIGGLY FENCE mirrorChars.put(0x29F5, 0x2215); // REVERSE SOLIDUS OPERATOR mirrorChars.put(0x29F8, 0x29F9); // BIG SOLIDUS mirrorChars.put(0x29F9, 0x29F8); // BIG REVERSE SOLIDUS mirrorChars.put(0x29FC, 0x29FD); // LEFT-POINTING CURVED ANGLE BRACKET mirrorChars.put(0x29FD, 0x29FC); // RIGHT-POINTING CURVED ANGLE BRACKET mirrorChars.put(0x2A2B, 0x2A2C); // MINUS SIGN WITH FALLING DOTS mirrorChars.put(0x2A2C, 0x2A2B); // MINUS SIGN WITH RISING DOTS mirrorChars.put(0x2A2D, 0x2A2C); // PLUS SIGN IN LEFT HALF CIRCLE mirrorChars.put(0x2A2E, 0x2A2D); // PLUS SIGN IN RIGHT HALF CIRCLE mirrorChars.put(0x2A34, 0x2A35); // MULTIPLICATION SIGN IN LEFT HALF CIRCLE mirrorChars.put(0x2A35, 0x2A34); // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE mirrorChars.put(0x2A3C, 0x2A3D); // INTERIOR PRODUCT mirrorChars.put(0x2A3D, 0x2A3C); // RIGHTHAND INTERIOR PRODUCT mirrorChars.put(0x2A64, 0x2A65); // Z NOTATION DOMAIN ANTIRESTRICTION mirrorChars.put(0x2A65, 0x2A64); // Z NOTATION RANGE ANTIRESTRICTION mirrorChars.put(0x2A79, 0x2A7A); // LESS-THAN WITH CIRCLE INSIDE mirrorChars.put(0x2A7A, 0x2A79); // GREATER-THAN WITH CIRCLE INSIDE mirrorChars.put(0x2A7D, 0x2A7E); // LESS-THAN OR SLANTED EQUAL TO mirrorChars.put(0x2A7E, 0x2A7D); // GREATER-THAN OR SLANTED EQUAL TO mirrorChars.put(0x2A7F, 0x2A80); // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE mirrorChars.put(0x2A80, 0x2A7F); // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE mirrorChars.put(0x2A81, 0x2A82); // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE mirrorChars.put(0x2A82, 0x2A81); // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE mirrorChars.put(0x2A83, 0x2A84); // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT mirrorChars.put(0x2A84, 0x2A83); // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT mirrorChars.put(0x2A8B, 0x2A8C); // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN mirrorChars.put(0x2A8C, 0x2A8B); // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN mirrorChars.put(0x2A91, 0x2A92); // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL mirrorChars.put(0x2A92, 0x2A91); // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL mirrorChars.put(0x2A93, 0x2A94); // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL mirrorChars.put(0x2A94, 0x2A93); // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL mirrorChars.put(0x2A95, 0x2A96); // SLANTED EQUAL TO OR LESS-THAN mirrorChars.put(0x2A96, 0x2A95); // SLANTED EQUAL TO OR GREATER-THAN mirrorChars.put(0x2A97, 0x2A98); // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE mirrorChars.put(0x2A98, 0x2A97); // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE mirrorChars.put(0x2A99, 0x2A9A); // DOUBLE-LINE EQUAL TO OR LESS-THAN mirrorChars.put(0x2A9A, 0x2A99); // DOUBLE-LINE EQUAL TO OR GREATER-THAN mirrorChars.put(0x2A9B, 0x2A9C); // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN mirrorChars.put(0x2A9C, 0x2A9B); // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN mirrorChars.put(0x2AA1, 0x2AA2); // DOUBLE NESTED LESS-THAN mirrorChars.put(0x2AA2, 0x2AA1); // DOUBLE NESTED GREATER-THAN mirrorChars.put(0x2AA6, 0x2AA7); // LESS-THAN CLOSED BY CURVE mirrorChars.put(0x2AA7, 0x2AA6); // GREATER-THAN CLOSED BY CURVE mirrorChars.put(0x2AA8, 0x2AA9); // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL mirrorChars.put(0x2AA9, 0x2AA8); // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL mirrorChars.put(0x2AAA, 0x2AAB); // SMALLER THAN mirrorChars.put(0x2AAB, 0x2AAA); // LARGER THAN mirrorChars.put(0x2AAC, 0x2AAD); // SMALLER THAN OR EQUAL TO mirrorChars.put(0x2AAD, 0x2AAC); // LARGER THAN OR EQUAL TO mirrorChars.put(0x2AAF, 0x2AB0); // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN mirrorChars.put(0x2AB0, 0x2AAF); // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN mirrorChars.put(0x2AB3, 0x2AB4); // PRECEDES ABOVE EQUALS SIGN mirrorChars.put(0x2AB4, 0x2AB3); // SUCCEEDS ABOVE EQUALS SIGN mirrorChars.put(0x2ABB, 0x2ABC); // DOUBLE PRECEDES mirrorChars.put(0x2ABC, 0x2ABB); // DOUBLE SUCCEEDS mirrorChars.put(0x2ABD, 0x2ABE); // SUBSET WITH DOT mirrorChars.put(0x2ABE, 0x2ABD); // SUPERSET WITH DOT mirrorChars.put(0x2ABF, 0x2AC0); // SUBSET WITH PLUS SIGN BELOW mirrorChars.put(0x2AC0, 0x2ABF); // SUPERSET WITH PLUS SIGN BELOW mirrorChars.put(0x2AC1, 0x2AC2); // SUBSET WITH MULTIPLICATION SIGN BELOW mirrorChars.put(0x2AC2, 0x2AC1); // SUPERSET WITH MULTIPLICATION SIGN BELOW mirrorChars.put(0x2AC3, 0x2AC4); // SUBSET OF OR EQUAL TO WITH DOT ABOVE mirrorChars.put(0x2AC4, 0x2AC3); // SUPERSET OF OR EQUAL TO WITH DOT ABOVE mirrorChars.put(0x2AC5, 0x2AC6); // SUBSET OF ABOVE EQUALS SIGN mirrorChars.put(0x2AC6, 0x2AC5); // SUPERSET OF ABOVE EQUALS SIGN mirrorChars.put(0x2ACD, 0x2ACE); // SQUARE LEFT OPEN BOX OPERATOR mirrorChars.put(0x2ACE, 0x2ACD); // SQUARE RIGHT OPEN BOX OPERATOR mirrorChars.put(0x2ACF, 0x2AD0); // CLOSED SUBSET mirrorChars.put(0x2AD0, 0x2ACF); // CLOSED SUPERSET mirrorChars.put(0x2AD1, 0x2AD2); // CLOSED SUBSET OR EQUAL TO mirrorChars.put(0x2AD2, 0x2AD1); // CLOSED SUPERSET OR EQUAL TO mirrorChars.put(0x2AD3, 0x2AD4); // SUBSET ABOVE SUPERSET mirrorChars.put(0x2AD4, 0x2AD3); // SUPERSET ABOVE SUBSET mirrorChars.put(0x2AD5, 0x2AD6); // SUBSET ABOVE SUBSET mirrorChars.put(0x2AD6, 0x2AD5); // SUPERSET ABOVE SUPERSET mirrorChars.put(0x2ADE, 0x22A6); // SHORT LEFT TACK mirrorChars.put(0x2AE3, 0x22A9); // DOUBLE VERTICAL BAR LEFT TURNSTILE mirrorChars.put(0x2AE4, 0x22A8); // VERTICAL BAR DOUBLE LEFT TURNSTILE mirrorChars.put(0x2AE5, 0x22AB); // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE mirrorChars.put(0x2AEC, 0x2AED); // DOUBLE STROKE NOT SIGN mirrorChars.put(0x2AED, 0x2AEC); // REVERSED DOUBLE STROKE NOT SIGN mirrorChars.put(0x2AF7, 0x2AF8); // TRIPLE NESTED LESS-THAN mirrorChars.put(0x2AF8, 0x2AF7); // TRIPLE NESTED GREATER-THAN mirrorChars.put(0x2AF9, 0x2AFA); // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO mirrorChars.put(0x2AFA, 0x2AF9); // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO mirrorChars.put(0x3008, 0x3009); // LEFT ANGLE BRACKET mirrorChars.put(0x3009, 0x3008); // RIGHT ANGLE BRACKET mirrorChars.put(0x300A, 0x300B); // LEFT DOUBLE ANGLE BRACKET mirrorChars.put(0x300B, 0x300A); // RIGHT DOUBLE ANGLE BRACKET mirrorChars.put(0x300C, 0x300D); // [BEST FIT] LEFT CORNER BRACKET mirrorChars.put(0x300D, 0x300C); // [BEST FIT] RIGHT CORNER BRACKET mirrorChars.put(0x300E, 0x300F); // [BEST FIT] LEFT WHITE CORNER BRACKET mirrorChars.put(0x300F, 0x300E); // [BEST FIT] RIGHT WHITE CORNER BRACKET mirrorChars.put(0x3010, 0x3011); // LEFT BLACK LENTICULAR BRACKET mirrorChars.put(0x3011, 0x3010); // RIGHT BLACK LENTICULAR BRACKET mirrorChars.put(0x3014, 0x3015); // LEFT TORTOISE SHELL BRACKET mirrorChars.put(0x3015, 0x3014); // RIGHT TORTOISE SHELL BRACKET mirrorChars.put(0x3016, 0x3017); // LEFT WHITE LENTICULAR BRACKET mirrorChars.put(0x3017, 0x3016); // RIGHT WHITE LENTICULAR BRACKET mirrorChars.put(0x3018, 0x3019); // LEFT WHITE TORTOISE SHELL BRACKET mirrorChars.put(0x3019, 0x3018); // RIGHT WHITE TORTOISE SHELL BRACKET mirrorChars.put(0x301A, 0x301B); // LEFT WHITE SQUARE BRACKET mirrorChars.put(0x301B, 0x301A); // RIGHT WHITE SQUARE BRACKET mirrorChars.put(0xFF08, 0xFF09); // FULLWIDTH LEFT PARENTHESIS mirrorChars.put(0xFF09, 0xFF08); // FULLWIDTH RIGHT PARENTHESIS mirrorChars.put(0xFF1C, 0xFF1E); // FULLWIDTH LESS-THAN SIGN mirrorChars.put(0xFF1E, 0xFF1C); // FULLWIDTH GREATER-THAN SIGN mirrorChars.put(0xFF3B, 0xFF3D); // FULLWIDTH LEFT SQUARE BRACKET mirrorChars.put(0xFF3D, 0xFF3B); // FULLWIDTH RIGHT SQUARE BRACKET mirrorChars.put(0xFF5B, 0xFF5D); // FULLWIDTH LEFT CURLY BRACKET mirrorChars.put(0xFF5D, 0xFF5B); // FULLWIDTH RIGHT CURLY BRACKET mirrorChars.put(0xFF5F, 0xFF60); // FULLWIDTH LEFT WHITE PARENTHESIS mirrorChars.put(0xFF60, 0xFF5F); // FULLWIDTH RIGHT WHITE PARENTHESIS mirrorChars.put(0xFF62, 0xFF63); // [BEST FIT] HALFWIDTH LEFT CORNER BRACKET mirrorChars.put(0xFF63, 0xFF62); // [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET } /** * Method that changes a String with Arabic characters into a String in which the ligatures are made. * @param s the original String * @param runDirection * @param arabicOptions * @return the String with the ligatures */ public static String processLTR(String s, int runDirection, int arabicOptions) { BidiLine bidi = new BidiLine(); bidi.addChunk(new PdfChunk(new Chunk(s), null)); bidi.arabicOptions = arabicOptions; bidi.getParagraph(runDirection); ArrayList<PdfChunk> arr = bidi.createArrayOfPdfChunks(0, bidi.totalTextLength - 1); StringBuilder sb = new StringBuilder(); for (PdfChunk ck : arr) { sb.append(ck.toString()); } return sb.toString(); } }
⏎ com/itextpdf/text/pdf/BidiLine.java
Or download all of them as a single archive file:
File name: itextpdf-5.5.14-fyi.zip File size: 2163839 bytes Release date: 2009-10-09 Download
⇒ iText-2.1.6.jar - iText, a JAVA-PDF library
⇐ iText layout.jar Source Code
2021-07-03, 132801👍, 0💬
Popular Posts:
Apache Log4j provides the interface that applications should code to and provides the adapter compon...
How to download and install JDK (Java Development Kit) 1.4? If you want to write Java applications, ...
commons-fileupload-1.3.3 -sources.jaris the source JAR file for Apache Commons FileUpload 1.3., whic...
How to merge two JAR files with "jar" commands? I am tired of specifying multiple JAR files in the c...
If you are a Java developer, it is very often that you need to use some 3rd party libraries to perfo...