001: /*
002: *
003: * Copyright 2002 Paulo Soares
004: *
005: * The contents of this file are subject to the Mozilla Public License Version 1.1
006: * (the "License"); you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS" basis,
010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: * for the specific language governing rights and limitations under the License.
012: *
013: * The Original Code is 'iText, a free JAVA-PDF library'.
014: *
015: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
016: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
017: * All Rights Reserved.
018: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
019: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
020: *
021: * Contributor(s): all the names of the contributors are added in the source code
022: * where applicable.
023: *
024: * Alternatively, the contents of this file may be used under the terms of the
025: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
026: * provisions of LGPL are applicable instead of those above. If you wish to
027: * allow use of your version of this file only under the terms of the LGPL
028: * License and not to allow others to use your version of this file under
029: * the MPL, indicate your decision by deleting the provisions above and
030: * replace them with the notice and other provisions required by the LGPL.
031: * If you do not delete the provisions above, a recipient may use your version
032: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
033: *
034: * This library is free software; you can redistribute it and/or modify it
035: * under the terms of the MPL as stated above or under the terms of the GNU
036: * Library General Public License as published by the Free Software Foundation;
037: * either version 2 of the License, or any later version.
038: *
039: * This library is distributed in the hope that it will be useful, but WITHOUT
040: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
041: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
042: * details.
043: *
044: * If you didn't download this code from the following link, you should check if
045: * you aren't using an obsolete version:
046: * http://www.lowagie.com/iText/
047: */
048:
049: package com.lowagie.text.pdf;
050:
051: import java.util.ArrayList;
052:
053: import com.lowagie.text.Chunk;
054:
055: /** Does all the line bidirectional processing with PdfChunk assembly.
056: *
057: * @author Paulo Soares (psoares@consiste.pt)
058: */
059: public class BidiLine {
060:
061: protected int runDirection;
062: protected int pieceSize = 256;
063: protected char text[] = new char[pieceSize];
064: protected PdfChunk detailChunks[] = new PdfChunk[pieceSize];
065: protected int totalTextLength = 0;
066:
067: protected byte orderLevels[] = new byte[pieceSize];
068: protected int indexChars[] = new int[pieceSize];
069:
070: protected ArrayList chunks = new ArrayList();
071: protected int indexChunk = 0;
072: protected int indexChunkChar = 0;
073: protected int currentChar = 0;
074:
075: protected int storedRunDirection;
076: protected char storedText[] = new char[0];
077: protected PdfChunk storedDetailChunks[] = new PdfChunk[0];
078: protected int storedTotalTextLength = 0;
079:
080: protected byte storedOrderLevels[] = new byte[0];
081: protected int storedIndexChars[] = new int[0];
082:
083: protected int storedIndexChunk = 0;
084: protected int storedIndexChunkChar = 0;
085: protected int storedCurrentChar = 0;
086:
087: protected boolean shortStore;
088: // protected ArabicShaping arabic = new ArabicShaping(ArabicShaping.LETTERS_SHAPE | ArabicShaping.LENGTH_GROW_SHRINK | ArabicShaping.TEXT_DIRECTION_LOGICAL);
089: protected static final IntHashtable mirrorChars = new IntHashtable();
090: protected int arabicOptions;
091:
092: /** Creates new BidiLine */
093: public BidiLine() {
094: }
095:
096: public BidiLine(BidiLine org) {
097: runDirection = org.runDirection;
098: pieceSize = org.pieceSize;
099: text = (char[]) org.text.clone();
100: detailChunks = (PdfChunk[]) org.detailChunks.clone();
101: totalTextLength = org.totalTextLength;
102:
103: orderLevels = (byte[]) org.orderLevels.clone();
104: indexChars = (int[]) org.indexChars.clone();
105:
106: chunks = new ArrayList(org.chunks);
107: indexChunk = org.indexChunk;
108: indexChunkChar = org.indexChunkChar;
109: currentChar = org.currentChar;
110:
111: storedRunDirection = org.storedRunDirection;
112: storedText = (char[]) org.storedText.clone();
113: storedDetailChunks = (PdfChunk[]) org.storedDetailChunks
114: .clone();
115: storedTotalTextLength = org.storedTotalTextLength;
116:
117: storedOrderLevels = (byte[]) org.storedOrderLevels.clone();
118: storedIndexChars = (int[]) org.storedIndexChars.clone();
119:
120: storedIndexChunk = org.storedIndexChunk;
121: storedIndexChunkChar = org.storedIndexChunkChar;
122: storedCurrentChar = org.storedCurrentChar;
123:
124: shortStore = org.shortStore;
125: arabicOptions = org.arabicOptions;
126: }
127:
128: public boolean isEmpty() {
129: return (currentChar >= totalTextLength && indexChunk >= chunks
130: .size());
131: }
132:
133: public void clearChunks() {
134: chunks.clear();
135: totalTextLength = 0;
136: currentChar = 0;
137: }
138:
139: public boolean getParagraph(int runDirection) {
140: this .runDirection = runDirection;
141: currentChar = 0;
142: totalTextLength = 0;
143: boolean hasText = false;
144: char c;
145: char uniC;
146: BaseFont bf;
147: for (; indexChunk < chunks.size(); ++indexChunk) {
148: PdfChunk ck = (PdfChunk) chunks.get(indexChunk);
149: bf = ck.font().getFont();
150: String s = ck.toString();
151: int len = s.length();
152: for (; indexChunkChar < len; ++indexChunkChar) {
153: c = s.charAt(indexChunkChar);
154: uniC = bf.getUnicodeEquivalent(c);
155: if (uniC == '\r' || uniC == '\n') {
156: // next condition is never true for CID
157: if (uniC == '\r' && indexChunkChar + 1 < len
158: && s.charAt(indexChunkChar + 1) == '\n')
159: ++indexChunkChar;
160: ++indexChunkChar;
161: if (indexChunkChar >= len) {
162: indexChunkChar = 0;
163: ++indexChunk;
164: }
165: hasText = true;
166: if (totalTextLength == 0)
167: detailChunks[0] = ck;
168: break;
169: }
170: addPiece(c, ck);
171: }
172: if (hasText)
173: break;
174: indexChunkChar = 0;
175: }
176: if (totalTextLength == 0)
177: return hasText;
178:
179: // remove trailing WS
180: totalTextLength = trimRight(0, totalTextLength - 1) + 1;
181: if (totalTextLength == 0)
182: return true;
183:
184: if (runDirection == PdfWriter.RUN_DIRECTION_LTR
185: || runDirection == PdfWriter.RUN_DIRECTION_RTL) {
186: if (orderLevels.length < totalTextLength) {
187: orderLevels = new byte[pieceSize];
188: indexChars = new int[pieceSize];
189: }
190: ArabicLigaturizer.processNumbers(text, 0, totalTextLength,
191: arabicOptions);
192: BidiOrder order = new BidiOrder(
193: text,
194: 0,
195: totalTextLength,
196: (byte) (runDirection == PdfWriter.RUN_DIRECTION_RTL ? 1
197: : 0));
198: byte od[] = order.getLevels();
199: for (int k = 0; k < totalTextLength; ++k) {
200: orderLevels[k] = od[k];
201: indexChars[k] = k;
202: }
203: doArabicShapping();
204: mirrorGlyphs();
205: }
206: totalTextLength = trimRightEx(0, totalTextLength - 1) + 1;
207: return true;
208: }
209:
210: public void addChunk(PdfChunk chunk) {
211: chunks.add(chunk);
212: }
213:
214: public void addChunks(ArrayList chunks) {
215: this .chunks.addAll(chunks);
216: }
217:
218: public void addPiece(char c, PdfChunk chunk) {
219: if (totalTextLength >= pieceSize) {
220: char tempText[] = text;
221: PdfChunk tempDetailChunks[] = detailChunks;
222: pieceSize *= 2;
223: text = new char[pieceSize];
224: detailChunks = new PdfChunk[pieceSize];
225: System.arraycopy(tempText, 0, text, 0, totalTextLength);
226: System.arraycopy(tempDetailChunks, 0, detailChunks, 0,
227: totalTextLength);
228: }
229: text[totalTextLength] = c;
230: detailChunks[totalTextLength++] = chunk;
231: }
232:
233: public void save() {
234: if (indexChunk > 0) {
235: if (indexChunk >= chunks.size())
236: chunks.clear();
237: else {
238: for (--indexChunk; indexChunk >= 0; --indexChunk)
239: chunks.remove(indexChunk);
240: }
241: indexChunk = 0;
242: }
243: storedRunDirection = runDirection;
244: storedTotalTextLength = totalTextLength;
245: storedIndexChunk = indexChunk;
246: storedIndexChunkChar = indexChunkChar;
247: storedCurrentChar = currentChar;
248: shortStore = (currentChar < totalTextLength);
249: if (!shortStore) {
250: // long save
251: if (storedText.length < totalTextLength) {
252: storedText = new char[totalTextLength];
253: storedDetailChunks = new PdfChunk[totalTextLength];
254: }
255: System.arraycopy(text, 0, storedText, 0, totalTextLength);
256: System.arraycopy(detailChunks, 0, storedDetailChunks, 0,
257: totalTextLength);
258: }
259: if (runDirection == PdfWriter.RUN_DIRECTION_LTR
260: || runDirection == PdfWriter.RUN_DIRECTION_RTL) {
261: if (storedOrderLevels.length < totalTextLength) {
262: storedOrderLevels = new byte[totalTextLength];
263: storedIndexChars = new int[totalTextLength];
264: }
265: System.arraycopy(orderLevels, currentChar,
266: storedOrderLevels, currentChar, totalTextLength
267: - currentChar);
268: System.arraycopy(indexChars, currentChar, storedIndexChars,
269: currentChar, totalTextLength - currentChar);
270: }
271: }
272:
273: public void restore() {
274: runDirection = storedRunDirection;
275: totalTextLength = storedTotalTextLength;
276: indexChunk = storedIndexChunk;
277: indexChunkChar = storedIndexChunkChar;
278: currentChar = storedCurrentChar;
279: if (!shortStore) {
280: // long restore
281: System.arraycopy(storedText, 0, text, 0, totalTextLength);
282: System.arraycopy(storedDetailChunks, 0, detailChunks, 0,
283: totalTextLength);
284: }
285: if (runDirection == PdfWriter.RUN_DIRECTION_LTR
286: || runDirection == PdfWriter.RUN_DIRECTION_RTL) {
287: System.arraycopy(storedOrderLevels, currentChar,
288: orderLevels, currentChar, totalTextLength
289: - currentChar);
290: System.arraycopy(storedIndexChars, currentChar, indexChars,
291: currentChar, totalTextLength - currentChar);
292: }
293: }
294:
295: public void mirrorGlyphs() {
296: for (int k = 0; k < totalTextLength; ++k) {
297: if ((orderLevels[k] & 1) == 1) {
298: int mirror = mirrorChars.get(text[k]);
299: if (mirror != 0)
300: text[k] = (char) mirror;
301: }
302: }
303: }
304:
305: public void doArabicShapping() {
306: int src = 0;
307: int dest = 0;
308: for (;;) {
309: while (src < totalTextLength) {
310: char c = text[src];
311: if (c >= 0x0600 && c <= 0x06ff)
312: break;
313: if (src != dest) {
314: text[dest] = text[src];
315: detailChunks[dest] = detailChunks[src];
316: orderLevels[dest] = orderLevels[src];
317: }
318: ++src;
319: ++dest;
320: }
321: if (src >= totalTextLength) {
322: totalTextLength = dest;
323: return;
324: }
325: int startArabicIdx = src;
326: ++src;
327: while (src < totalTextLength) {
328: char c = text[src];
329: if (c < 0x0600 || c > 0x06ff)
330: break;
331: ++src;
332: }
333: int arabicWordSize = src - startArabicIdx;
334: int size = ArabicLigaturizer
335: .arabic_shape(text, startArabicIdx, arabicWordSize,
336: text, dest, arabicWordSize, arabicOptions /*PangoArabicShapping.ar_novowel PangoArabicShapping.ar_lig | PangoArabicShapping.ar_composedtashkeel*/);
337: if (startArabicIdx != dest) {
338: for (int k = 0; k < size; ++k) {
339: detailChunks[dest] = detailChunks[startArabicIdx];
340: orderLevels[dest++] = orderLevels[startArabicIdx++];
341: }
342: } else
343: dest += size;
344: }
345: }
346:
347: public PdfLine processLine(float width, int alignment,
348: int runDirection, int arabicOptions) {
349: this .arabicOptions = arabicOptions;
350: save();
351: boolean isRTL = (runDirection == PdfWriter.RUN_DIRECTION_RTL);
352: if (currentChar >= totalTextLength) {
353: boolean hasText = getParagraph(runDirection);
354: if (!hasText)
355: return null;
356: if (totalTextLength == 0) {
357: ArrayList ar = new ArrayList();
358: PdfChunk ck = new PdfChunk("", detailChunks[0]);
359: ar.add(ck);
360: return new PdfLine(0, 0, alignment, true, ar, isRTL);
361: }
362: }
363: float originalWidth = width;
364: int lastSplit = -1;
365: if (currentChar != 0)
366: currentChar = trimLeftEx(currentChar, totalTextLength - 1);
367: int oldCurrentChar = currentChar;
368: char c = 0;
369: char uniC = 0;
370: PdfChunk ck = null;
371: float charWidth = 0;
372: PdfChunk lastValidChunk = null;
373: for (; currentChar < totalTextLength; ++currentChar) {
374: c = text[currentChar];
375: ck = detailChunks[currentChar];
376: uniC = ck.getUnicodeEquivalent(c);
377: if (PdfChunk.noPrint(uniC))
378: continue;
379: charWidth = ck.getCharWidth(c);
380: if (ck.isExtSplitCharacter(oldCurrentChar, currentChar,
381: totalTextLength, text, detailChunks))
382: lastSplit = currentChar;
383: if (width - charWidth < 0)
384: break;
385: width -= charWidth;
386: lastValidChunk = ck;
387: }
388: if (lastValidChunk == null) {
389: // not even a single char fit; must output the first char
390: ++currentChar;
391: return new PdfLine(0, 0, alignment, false,
392: createArrayOfPdfChunks(currentChar - 1,
393: currentChar - 1), isRTL);
394: }
395: if (currentChar >= totalTextLength) {
396: // there was more line than text
397: return new PdfLine(0, width, alignment, true,
398: createArrayOfPdfChunks(oldCurrentChar,
399: totalTextLength - 1), isRTL);
400: }
401: int newCurrentChar = trimRightEx(oldCurrentChar,
402: currentChar - 1);
403: if (newCurrentChar < oldCurrentChar) {
404: // only WS
405: return new PdfLine(0, width, alignment, false,
406: createArrayOfPdfChunks(oldCurrentChar,
407: currentChar - 1), isRTL);
408: }
409: if (newCurrentChar == currentChar - 1) { // middle of word
410: HyphenationEvent he = (HyphenationEvent) lastValidChunk
411: .getAttribute(Chunk.HYPHENATION);
412: if (he != null) {
413: int word[] = getWord(oldCurrentChar, newCurrentChar);
414: if (word != null) {
415: float testWidth = width
416: + getWidth(word[0], currentChar - 1);
417: String pre = he.getHyphenatedWordPre(new String(
418: text, word[0], word[1] - word[0]),
419: lastValidChunk.font().getFont(),
420: lastValidChunk.font().size(), testWidth);
421: String post = he.getHyphenatedWordPost();
422: if (pre.length() > 0) {
423: PdfChunk extra = new PdfChunk(pre,
424: lastValidChunk);
425: currentChar = word[1] - post.length();
426: return new PdfLine(0, testWidth
427: - lastValidChunk.font().width(pre),
428: alignment, false,
429: createArrayOfPdfChunks(oldCurrentChar,
430: word[0] - 1, extra), isRTL);
431: }
432: }
433: }
434: }
435: if (lastSplit == -1 || lastSplit >= newCurrentChar) {
436: // no split point or split point ahead of end
437: return new PdfLine(0, width
438: + getWidth(newCurrentChar + 1, currentChar - 1),
439: alignment, false, createArrayOfPdfChunks(
440: oldCurrentChar, newCurrentChar), isRTL);
441: }
442: // standard split
443: currentChar = lastSplit + 1;
444: newCurrentChar = trimRightEx(oldCurrentChar, lastSplit);
445: if (newCurrentChar < oldCurrentChar) {
446: // only WS again
447: newCurrentChar = currentChar - 1;
448: }
449: return new PdfLine(0, originalWidth
450: - getWidth(oldCurrentChar, newCurrentChar), alignment,
451: false, createArrayOfPdfChunks(oldCurrentChar,
452: newCurrentChar), isRTL);
453: }
454:
455: /** Gets the width of a range of characters.
456: * @param startIdx the first index to calculate
457: * @param lastIdx the last inclusive index to calculate
458: * @return the sum of all widths
459: */
460: public float getWidth(int startIdx, int lastIdx) {
461: char c = 0;
462: char uniC;
463: PdfChunk ck = null;
464: float width = 0;
465: for (; startIdx <= lastIdx; ++startIdx) {
466: c = text[startIdx];
467: ck = detailChunks[startIdx];
468: uniC = ck.getUnicodeEquivalent(c);
469: if (PdfChunk.noPrint(uniC))
470: continue;
471: width += detailChunks[startIdx].getCharWidth(c);
472: }
473: return width;
474: }
475:
476: public ArrayList createArrayOfPdfChunks(int startIdx, int endIdx) {
477: return createArrayOfPdfChunks(startIdx, endIdx, null);
478: }
479:
480: public ArrayList createArrayOfPdfChunks(int startIdx, int endIdx,
481: PdfChunk extraPdfChunk) {
482: boolean bidi = (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL);
483: if (bidi)
484: reorder(startIdx, endIdx);
485: ArrayList ar = new ArrayList();
486: PdfChunk refCk = detailChunks[startIdx];
487: PdfChunk ck = null;
488: StringBuffer buf = new StringBuffer();
489: char c;
490: int idx = 0;
491: for (; startIdx <= endIdx; ++startIdx) {
492: idx = bidi ? indexChars[startIdx] : startIdx;
493: c = text[idx];
494: ck = detailChunks[idx];
495: if (PdfChunk.noPrint(ck.getUnicodeEquivalent(c)))
496: continue;
497: if (ck.isImage()) {
498: if (buf.length() > 0) {
499: ar.add(new PdfChunk(buf.toString(), refCk));
500: buf = new StringBuffer();
501: }
502: ar.add(ck);
503: } else if (ck == refCk) {
504: buf.append(c);
505: } else {
506: if (buf.length() > 0) {
507: ar.add(new PdfChunk(buf.toString(), refCk));
508: buf = new StringBuffer();
509: }
510: if (!ck.isImage())
511: buf.append(c);
512: refCk = ck;
513: }
514: }
515: if (buf.length() > 0) {
516: ar.add(new PdfChunk(buf.toString(), refCk));
517: }
518: if (extraPdfChunk != null)
519: ar.add(extraPdfChunk);
520: return ar;
521: }
522:
523: public int[] getWord(int startIdx, int idx) {
524: int last = idx;
525: int first = idx;
526: // forward
527: for (; last < totalTextLength; ++last) {
528: if (!Character.isLetter(text[last]))
529: break;
530: }
531: if (last == idx)
532: return null;
533: // backward
534: for (; first >= startIdx; --first) {
535: if (!Character.isLetter(text[first]))
536: break;
537: }
538: ++first;
539: return new int[] { first, last };
540: }
541:
542: public int trimRight(int startIdx, int endIdx) {
543: int idx = endIdx;
544: char c;
545: for (; idx >= startIdx; --idx) {
546: c = detailChunks[idx].getUnicodeEquivalent(text[idx]);
547: if (!isWS(c))
548: break;
549: }
550: return idx;
551: }
552:
553: public int trimLeft(int startIdx, int endIdx) {
554: int idx = startIdx;
555: char c;
556: for (; idx <= endIdx; ++idx) {
557: c = detailChunks[idx].getUnicodeEquivalent(text[idx]);
558: if (!isWS(c))
559: break;
560: }
561: return idx;
562: }
563:
564: public int trimRightEx(int startIdx, int endIdx) {
565: int idx = endIdx;
566: char c = 0;
567: for (; idx >= startIdx; --idx) {
568: c = detailChunks[idx].getUnicodeEquivalent(text[idx]);
569: if (!isWS(c) && !PdfChunk.noPrint(c))
570: break;
571: }
572: return idx;
573: }
574:
575: public int trimLeftEx(int startIdx, int endIdx) {
576: int idx = startIdx;
577: char c = 0;
578: for (; idx <= endIdx; ++idx) {
579: c = detailChunks[idx].getUnicodeEquivalent(text[idx]);
580: if (!isWS(c) && !PdfChunk.noPrint(c))
581: break;
582: }
583: return idx;
584: }
585:
586: public void reorder(int start, int end) {
587: byte maxLevel = orderLevels[start];
588: byte minLevel = maxLevel;
589: byte onlyOddLevels = maxLevel;
590: byte onlyEvenLevels = maxLevel;
591: for (int k = start + 1; k <= end; ++k) {
592: byte b = orderLevels[k];
593: if (b > maxLevel)
594: maxLevel = b;
595: else if (b < minLevel)
596: minLevel = b;
597: onlyOddLevels &= b;
598: onlyEvenLevels |= b;
599: }
600: if ((onlyEvenLevels & 1) == 0) // nothing to do
601: return;
602: if ((onlyOddLevels & 1) == 1) { // single inversion
603: flip(start, end + 1);
604: return;
605: }
606: minLevel |= 1;
607: for (; maxLevel >= minLevel; --maxLevel) {
608: int pstart = start;
609: for (;;) {
610: for (; pstart <= end; ++pstart) {
611: if (orderLevels[pstart] >= maxLevel)
612: break;
613: }
614: if (pstart > end)
615: break;
616: int pend = pstart + 1;
617: for (; pend <= end; ++pend) {
618: if (orderLevels[pend] < maxLevel)
619: break;
620: }
621: flip(pstart, pend);
622: pstart = pend + 1;
623: }
624: }
625: }
626:
627: public void flip(int start, int end) {
628: int mid = (start + end) / 2;
629: --end;
630: for (; start < mid; ++start, --end) {
631: int temp = indexChars[start];
632: indexChars[start] = indexChars[end];
633: indexChars[end] = temp;
634: }
635: }
636:
637: public static boolean isWS(char c) {
638: return (c <= ' ');
639: }
640:
641: static {
642: mirrorChars.put(0x0028, 0x0029); // LEFT PARENTHESIS
643: mirrorChars.put(0x0029, 0x0028); // RIGHT PARENTHESIS
644: mirrorChars.put(0x003C, 0x003E); // LESS-THAN SIGN
645: mirrorChars.put(0x003E, 0x003C); // GREATER-THAN SIGN
646: mirrorChars.put(0x005B, 0x005D); // LEFT SQUARE BRACKET
647: mirrorChars.put(0x005D, 0x005B); // RIGHT SQUARE BRACKET
648: mirrorChars.put(0x007B, 0x007D); // LEFT CURLY BRACKET
649: mirrorChars.put(0x007D, 0x007B); // RIGHT CURLY BRACKET
650: mirrorChars.put(0x00AB, 0x00BB); // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
651: mirrorChars.put(0x00BB, 0x00AB); // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
652: mirrorChars.put(0x2039, 0x203A); // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
653: mirrorChars.put(0x203A, 0x2039); // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
654: mirrorChars.put(0x2045, 0x2046); // LEFT SQUARE BRACKET WITH QUILL
655: mirrorChars.put(0x2046, 0x2045); // RIGHT SQUARE BRACKET WITH QUILL
656: mirrorChars.put(0x207D, 0x207E); // SUPERSCRIPT LEFT PARENTHESIS
657: mirrorChars.put(0x207E, 0x207D); // SUPERSCRIPT RIGHT PARENTHESIS
658: mirrorChars.put(0x208D, 0x208E); // SUBSCRIPT LEFT PARENTHESIS
659: mirrorChars.put(0x208E, 0x208D); // SUBSCRIPT RIGHT PARENTHESIS
660: mirrorChars.put(0x2208, 0x220B); // ELEMENT OF
661: mirrorChars.put(0x2209, 0x220C); // NOT AN ELEMENT OF
662: mirrorChars.put(0x220A, 0x220D); // SMALL ELEMENT OF
663: mirrorChars.put(0x220B, 0x2208); // CONTAINS AS MEMBER
664: mirrorChars.put(0x220C, 0x2209); // DOES NOT CONTAIN AS MEMBER
665: mirrorChars.put(0x220D, 0x220A); // SMALL CONTAINS AS MEMBER
666: mirrorChars.put(0x2215, 0x29F5); // DIVISION SLASH
667: mirrorChars.put(0x223C, 0x223D); // TILDE OPERATOR
668: mirrorChars.put(0x223D, 0x223C); // REVERSED TILDE
669: mirrorChars.put(0x2243, 0x22CD); // ASYMPTOTICALLY EQUAL TO
670: mirrorChars.put(0x2252, 0x2253); // APPROXIMATELY EQUAL TO OR THE IMAGE OF
671: mirrorChars.put(0x2253, 0x2252); // IMAGE OF OR APPROXIMATELY EQUAL TO
672: mirrorChars.put(0x2254, 0x2255); // COLON EQUALS
673: mirrorChars.put(0x2255, 0x2254); // EQUALS COLON
674: mirrorChars.put(0x2264, 0x2265); // LESS-THAN OR EQUAL TO
675: mirrorChars.put(0x2265, 0x2264); // GREATER-THAN OR EQUAL TO
676: mirrorChars.put(0x2266, 0x2267); // LESS-THAN OVER EQUAL TO
677: mirrorChars.put(0x2267, 0x2266); // GREATER-THAN OVER EQUAL TO
678: mirrorChars.put(0x2268, 0x2269); // [BEST FIT] LESS-THAN BUT NOT EQUAL TO
679: mirrorChars.put(0x2269, 0x2268); // [BEST FIT] GREATER-THAN BUT NOT EQUAL TO
680: mirrorChars.put(0x226A, 0x226B); // MUCH LESS-THAN
681: mirrorChars.put(0x226B, 0x226A); // MUCH GREATER-THAN
682: mirrorChars.put(0x226E, 0x226F); // [BEST FIT] NOT LESS-THAN
683: mirrorChars.put(0x226F, 0x226E); // [BEST FIT] NOT GREATER-THAN
684: mirrorChars.put(0x2270, 0x2271); // [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO
685: mirrorChars.put(0x2271, 0x2270); // [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO
686: mirrorChars.put(0x2272, 0x2273); // [BEST FIT] LESS-THAN OR EQUIVALENT TO
687: mirrorChars.put(0x2273, 0x2272); // [BEST FIT] GREATER-THAN OR EQUIVALENT TO
688: mirrorChars.put(0x2274, 0x2275); // [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO
689: mirrorChars.put(0x2275, 0x2274); // [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO
690: mirrorChars.put(0x2276, 0x2277); // LESS-THAN OR GREATER-THAN
691: mirrorChars.put(0x2277, 0x2276); // GREATER-THAN OR LESS-THAN
692: mirrorChars.put(0x2278, 0x2279); // NEITHER LESS-THAN NOR GREATER-THAN
693: mirrorChars.put(0x2279, 0x2278); // NEITHER GREATER-THAN NOR LESS-THAN
694: mirrorChars.put(0x227A, 0x227B); // PRECEDES
695: mirrorChars.put(0x227B, 0x227A); // SUCCEEDS
696: mirrorChars.put(0x227C, 0x227D); // PRECEDES OR EQUAL TO
697: mirrorChars.put(0x227D, 0x227C); // SUCCEEDS OR EQUAL TO
698: mirrorChars.put(0x227E, 0x227F); // [BEST FIT] PRECEDES OR EQUIVALENT TO
699: mirrorChars.put(0x227F, 0x227E); // [BEST FIT] SUCCEEDS OR EQUIVALENT TO
700: mirrorChars.put(0x2280, 0x2281); // [BEST FIT] DOES NOT PRECEDE
701: mirrorChars.put(0x2281, 0x2280); // [BEST FIT] DOES NOT SUCCEED
702: mirrorChars.put(0x2282, 0x2283); // SUBSET OF
703: mirrorChars.put(0x2283, 0x2282); // SUPERSET OF
704: mirrorChars.put(0x2284, 0x2285); // [BEST FIT] NOT A SUBSET OF
705: mirrorChars.put(0x2285, 0x2284); // [BEST FIT] NOT A SUPERSET OF
706: mirrorChars.put(0x2286, 0x2287); // SUBSET OF OR EQUAL TO
707: mirrorChars.put(0x2287, 0x2286); // SUPERSET OF OR EQUAL TO
708: mirrorChars.put(0x2288, 0x2289); // [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO
709: mirrorChars.put(0x2289, 0x2288); // [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO
710: mirrorChars.put(0x228A, 0x228B); // [BEST FIT] SUBSET OF WITH NOT EQUAL TO
711: mirrorChars.put(0x228B, 0x228A); // [BEST FIT] SUPERSET OF WITH NOT EQUAL TO
712: mirrorChars.put(0x228F, 0x2290); // SQUARE IMAGE OF
713: mirrorChars.put(0x2290, 0x228F); // SQUARE ORIGINAL OF
714: mirrorChars.put(0x2291, 0x2292); // SQUARE IMAGE OF OR EQUAL TO
715: mirrorChars.put(0x2292, 0x2291); // SQUARE ORIGINAL OF OR EQUAL TO
716: mirrorChars.put(0x2298, 0x29B8); // CIRCLED DIVISION SLASH
717: mirrorChars.put(0x22A2, 0x22A3); // RIGHT TACK
718: mirrorChars.put(0x22A3, 0x22A2); // LEFT TACK
719: mirrorChars.put(0x22A6, 0x2ADE); // ASSERTION
720: mirrorChars.put(0x22A8, 0x2AE4); // TRUE
721: mirrorChars.put(0x22A9, 0x2AE3); // FORCES
722: mirrorChars.put(0x22AB, 0x2AE5); // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
723: mirrorChars.put(0x22B0, 0x22B1); // PRECEDES UNDER RELATION
724: mirrorChars.put(0x22B1, 0x22B0); // SUCCEEDS UNDER RELATION
725: mirrorChars.put(0x22B2, 0x22B3); // NORMAL SUBGROUP OF
726: mirrorChars.put(0x22B3, 0x22B2); // CONTAINS AS NORMAL SUBGROUP
727: mirrorChars.put(0x22B4, 0x22B5); // NORMAL SUBGROUP OF OR EQUAL TO
728: mirrorChars.put(0x22B5, 0x22B4); // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
729: mirrorChars.put(0x22B6, 0x22B7); // ORIGINAL OF
730: mirrorChars.put(0x22B7, 0x22B6); // IMAGE OF
731: mirrorChars.put(0x22C9, 0x22CA); // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
732: mirrorChars.put(0x22CA, 0x22C9); // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
733: mirrorChars.put(0x22CB, 0x22CC); // LEFT SEMIDIRECT PRODUCT
734: mirrorChars.put(0x22CC, 0x22CB); // RIGHT SEMIDIRECT PRODUCT
735: mirrorChars.put(0x22CD, 0x2243); // REVERSED TILDE EQUALS
736: mirrorChars.put(0x22D0, 0x22D1); // DOUBLE SUBSET
737: mirrorChars.put(0x22D1, 0x22D0); // DOUBLE SUPERSET
738: mirrorChars.put(0x22D6, 0x22D7); // LESS-THAN WITH DOT
739: mirrorChars.put(0x22D7, 0x22D6); // GREATER-THAN WITH DOT
740: mirrorChars.put(0x22D8, 0x22D9); // VERY MUCH LESS-THAN
741: mirrorChars.put(0x22D9, 0x22D8); // VERY MUCH GREATER-THAN
742: mirrorChars.put(0x22DA, 0x22DB); // LESS-THAN EQUAL TO OR GREATER-THAN
743: mirrorChars.put(0x22DB, 0x22DA); // GREATER-THAN EQUAL TO OR LESS-THAN
744: mirrorChars.put(0x22DC, 0x22DD); // EQUAL TO OR LESS-THAN
745: mirrorChars.put(0x22DD, 0x22DC); // EQUAL TO OR GREATER-THAN
746: mirrorChars.put(0x22DE, 0x22DF); // EQUAL TO OR PRECEDES
747: mirrorChars.put(0x22DF, 0x22DE); // EQUAL TO OR SUCCEEDS
748: mirrorChars.put(0x22E0, 0x22E1); // [BEST FIT] DOES NOT PRECEDE OR EQUAL
749: mirrorChars.put(0x22E1, 0x22E0); // [BEST FIT] DOES NOT SUCCEED OR EQUAL
750: mirrorChars.put(0x22E2, 0x22E3); // [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO
751: mirrorChars.put(0x22E3, 0x22E2); // [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO
752: mirrorChars.put(0x22E4, 0x22E5); // [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO
753: mirrorChars.put(0x22E5, 0x22E4); // [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO
754: mirrorChars.put(0x22E6, 0x22E7); // [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO
755: mirrorChars.put(0x22E7, 0x22E6); // [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO
756: mirrorChars.put(0x22E8, 0x22E9); // [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO
757: mirrorChars.put(0x22E9, 0x22E8); // [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO
758: mirrorChars.put(0x22EA, 0x22EB); // [BEST FIT] NOT NORMAL SUBGROUP OF
759: mirrorChars.put(0x22EB, 0x22EA); // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP
760: mirrorChars.put(0x22EC, 0x22ED); // [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO
761: mirrorChars.put(0x22ED, 0x22EC); // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
762: mirrorChars.put(0x22F0, 0x22F1); // UP RIGHT DIAGONAL ELLIPSIS
763: mirrorChars.put(0x22F1, 0x22F0); // DOWN RIGHT DIAGONAL ELLIPSIS
764: mirrorChars.put(0x22F2, 0x22FA); // ELEMENT OF WITH LONG HORIZONTAL STROKE
765: mirrorChars.put(0x22F3, 0x22FB); // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
766: mirrorChars.put(0x22F4, 0x22FC); // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
767: mirrorChars.put(0x22F6, 0x22FD); // ELEMENT OF WITH OVERBAR
768: mirrorChars.put(0x22F7, 0x22FE); // SMALL ELEMENT OF WITH OVERBAR
769: mirrorChars.put(0x22FA, 0x22F2); // CONTAINS WITH LONG HORIZONTAL STROKE
770: mirrorChars.put(0x22FB, 0x22F3); // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
771: mirrorChars.put(0x22FC, 0x22F4); // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
772: mirrorChars.put(0x22FD, 0x22F6); // CONTAINS WITH OVERBAR
773: mirrorChars.put(0x22FE, 0x22F7); // SMALL CONTAINS WITH OVERBAR
774: mirrorChars.put(0x2308, 0x2309); // LEFT CEILING
775: mirrorChars.put(0x2309, 0x2308); // RIGHT CEILING
776: mirrorChars.put(0x230A, 0x230B); // LEFT FLOOR
777: mirrorChars.put(0x230B, 0x230A); // RIGHT FLOOR
778: mirrorChars.put(0x2329, 0x232A); // LEFT-POINTING ANGLE BRACKET
779: mirrorChars.put(0x232A, 0x2329); // RIGHT-POINTING ANGLE BRACKET
780: mirrorChars.put(0x2768, 0x2769); // MEDIUM LEFT PARENTHESIS ORNAMENT
781: mirrorChars.put(0x2769, 0x2768); // MEDIUM RIGHT PARENTHESIS ORNAMENT
782: mirrorChars.put(0x276A, 0x276B); // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
783: mirrorChars.put(0x276B, 0x276A); // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
784: mirrorChars.put(0x276C, 0x276D); // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
785: mirrorChars.put(0x276D, 0x276C); // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
786: mirrorChars.put(0x276E, 0x276F); // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
787: mirrorChars.put(0x276F, 0x276E); // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
788: mirrorChars.put(0x2770, 0x2771); // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
789: mirrorChars.put(0x2771, 0x2770); // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
790: mirrorChars.put(0x2772, 0x2773); // LIGHT LEFT TORTOISE SHELL BRACKET
791: mirrorChars.put(0x2773, 0x2772); // LIGHT RIGHT TORTOISE SHELL BRACKET
792: mirrorChars.put(0x2774, 0x2775); // MEDIUM LEFT CURLY BRACKET ORNAMENT
793: mirrorChars.put(0x2775, 0x2774); // MEDIUM RIGHT CURLY BRACKET ORNAMENT
794: mirrorChars.put(0x27D5, 0x27D6); // LEFT OUTER JOIN
795: mirrorChars.put(0x27D6, 0x27D5); // RIGHT OUTER JOIN
796: mirrorChars.put(0x27DD, 0x27DE); // LONG RIGHT TACK
797: mirrorChars.put(0x27DE, 0x27DD); // LONG LEFT TACK
798: mirrorChars.put(0x27E2, 0x27E3); // WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK
799: mirrorChars.put(0x27E3, 0x27E2); // WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK
800: mirrorChars.put(0x27E4, 0x27E5); // WHITE SQUARE WITH LEFTWARDS TICK
801: mirrorChars.put(0x27E5, 0x27E4); // WHITE SQUARE WITH RIGHTWARDS TICK
802: mirrorChars.put(0x27E6, 0x27E7); // MATHEMATICAL LEFT WHITE SQUARE BRACKET
803: mirrorChars.put(0x27E7, 0x27E6); // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
804: mirrorChars.put(0x27E8, 0x27E9); // MATHEMATICAL LEFT ANGLE BRACKET
805: mirrorChars.put(0x27E9, 0x27E8); // MATHEMATICAL RIGHT ANGLE BRACKET
806: mirrorChars.put(0x27EA, 0x27EB); // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
807: mirrorChars.put(0x27EB, 0x27EA); // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
808: mirrorChars.put(0x2983, 0x2984); // LEFT WHITE CURLY BRACKET
809: mirrorChars.put(0x2984, 0x2983); // RIGHT WHITE CURLY BRACKET
810: mirrorChars.put(0x2985, 0x2986); // LEFT WHITE PARENTHESIS
811: mirrorChars.put(0x2986, 0x2985); // RIGHT WHITE PARENTHESIS
812: mirrorChars.put(0x2987, 0x2988); // Z NOTATION LEFT IMAGE BRACKET
813: mirrorChars.put(0x2988, 0x2987); // Z NOTATION RIGHT IMAGE BRACKET
814: mirrorChars.put(0x2989, 0x298A); // Z NOTATION LEFT BINDING BRACKET
815: mirrorChars.put(0x298A, 0x2989); // Z NOTATION RIGHT BINDING BRACKET
816: mirrorChars.put(0x298B, 0x298C); // LEFT SQUARE BRACKET WITH UNDERBAR
817: mirrorChars.put(0x298C, 0x298B); // RIGHT SQUARE BRACKET WITH UNDERBAR
818: mirrorChars.put(0x298D, 0x2990); // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
819: mirrorChars.put(0x298E, 0x298F); // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
820: mirrorChars.put(0x298F, 0x298E); // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
821: mirrorChars.put(0x2990, 0x298D); // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
822: mirrorChars.put(0x2991, 0x2992); // LEFT ANGLE BRACKET WITH DOT
823: mirrorChars.put(0x2992, 0x2991); // RIGHT ANGLE BRACKET WITH DOT
824: mirrorChars.put(0x2993, 0x2994); // LEFT ARC LESS-THAN BRACKET
825: mirrorChars.put(0x2994, 0x2993); // RIGHT ARC GREATER-THAN BRACKET
826: mirrorChars.put(0x2995, 0x2996); // DOUBLE LEFT ARC GREATER-THAN BRACKET
827: mirrorChars.put(0x2996, 0x2995); // DOUBLE RIGHT ARC LESS-THAN BRACKET
828: mirrorChars.put(0x2997, 0x2998); // LEFT BLACK TORTOISE SHELL BRACKET
829: mirrorChars.put(0x2998, 0x2997); // RIGHT BLACK TORTOISE SHELL BRACKET
830: mirrorChars.put(0x29B8, 0x2298); // CIRCLED REVERSE SOLIDUS
831: mirrorChars.put(0x29C0, 0x29C1); // CIRCLED LESS-THAN
832: mirrorChars.put(0x29C1, 0x29C0); // CIRCLED GREATER-THAN
833: mirrorChars.put(0x29C4, 0x29C5); // SQUARED RISING DIAGONAL SLASH
834: mirrorChars.put(0x29C5, 0x29C4); // SQUARED FALLING DIAGONAL SLASH
835: mirrorChars.put(0x29CF, 0x29D0); // LEFT TRIANGLE BESIDE VERTICAL BAR
836: mirrorChars.put(0x29D0, 0x29CF); // VERTICAL BAR BESIDE RIGHT TRIANGLE
837: mirrorChars.put(0x29D1, 0x29D2); // BOWTIE WITH LEFT HALF BLACK
838: mirrorChars.put(0x29D2, 0x29D1); // BOWTIE WITH RIGHT HALF BLACK
839: mirrorChars.put(0x29D4, 0x29D5); // TIMES WITH LEFT HALF BLACK
840: mirrorChars.put(0x29D5, 0x29D4); // TIMES WITH RIGHT HALF BLACK
841: mirrorChars.put(0x29D8, 0x29D9); // LEFT WIGGLY FENCE
842: mirrorChars.put(0x29D9, 0x29D8); // RIGHT WIGGLY FENCE
843: mirrorChars.put(0x29DA, 0x29DB); // LEFT DOUBLE WIGGLY FENCE
844: mirrorChars.put(0x29DB, 0x29DA); // RIGHT DOUBLE WIGGLY FENCE
845: mirrorChars.put(0x29F5, 0x2215); // REVERSE SOLIDUS OPERATOR
846: mirrorChars.put(0x29F8, 0x29F9); // BIG SOLIDUS
847: mirrorChars.put(0x29F9, 0x29F8); // BIG REVERSE SOLIDUS
848: mirrorChars.put(0x29FC, 0x29FD); // LEFT-POINTING CURVED ANGLE BRACKET
849: mirrorChars.put(0x29FD, 0x29FC); // RIGHT-POINTING CURVED ANGLE BRACKET
850: mirrorChars.put(0x2A2B, 0x2A2C); // MINUS SIGN WITH FALLING DOTS
851: mirrorChars.put(0x2A2C, 0x2A2B); // MINUS SIGN WITH RISING DOTS
852: mirrorChars.put(0x2A2D, 0x2A2C); // PLUS SIGN IN LEFT HALF CIRCLE
853: mirrorChars.put(0x2A2E, 0x2A2D); // PLUS SIGN IN RIGHT HALF CIRCLE
854: mirrorChars.put(0x2A34, 0x2A35); // MULTIPLICATION SIGN IN LEFT HALF CIRCLE
855: mirrorChars.put(0x2A35, 0x2A34); // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
856: mirrorChars.put(0x2A3C, 0x2A3D); // INTERIOR PRODUCT
857: mirrorChars.put(0x2A3D, 0x2A3C); // RIGHTHAND INTERIOR PRODUCT
858: mirrorChars.put(0x2A64, 0x2A65); // Z NOTATION DOMAIN ANTIRESTRICTION
859: mirrorChars.put(0x2A65, 0x2A64); // Z NOTATION RANGE ANTIRESTRICTION
860: mirrorChars.put(0x2A79, 0x2A7A); // LESS-THAN WITH CIRCLE INSIDE
861: mirrorChars.put(0x2A7A, 0x2A79); // GREATER-THAN WITH CIRCLE INSIDE
862: mirrorChars.put(0x2A7D, 0x2A7E); // LESS-THAN OR SLANTED EQUAL TO
863: mirrorChars.put(0x2A7E, 0x2A7D); // GREATER-THAN OR SLANTED EQUAL TO
864: mirrorChars.put(0x2A7F, 0x2A80); // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
865: mirrorChars.put(0x2A80, 0x2A7F); // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
866: mirrorChars.put(0x2A81, 0x2A82); // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
867: mirrorChars.put(0x2A82, 0x2A81); // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
868: mirrorChars.put(0x2A83, 0x2A84); // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
869: mirrorChars.put(0x2A84, 0x2A83); // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
870: mirrorChars.put(0x2A8B, 0x2A8C); // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
871: mirrorChars.put(0x2A8C, 0x2A8B); // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
872: mirrorChars.put(0x2A91, 0x2A92); // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
873: mirrorChars.put(0x2A92, 0x2A91); // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
874: mirrorChars.put(0x2A93, 0x2A94); // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
875: mirrorChars.put(0x2A94, 0x2A93); // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
876: mirrorChars.put(0x2A95, 0x2A96); // SLANTED EQUAL TO OR LESS-THAN
877: mirrorChars.put(0x2A96, 0x2A95); // SLANTED EQUAL TO OR GREATER-THAN
878: mirrorChars.put(0x2A97, 0x2A98); // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
879: mirrorChars.put(0x2A98, 0x2A97); // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
880: mirrorChars.put(0x2A99, 0x2A9A); // DOUBLE-LINE EQUAL TO OR LESS-THAN
881: mirrorChars.put(0x2A9A, 0x2A99); // DOUBLE-LINE EQUAL TO OR GREATER-THAN
882: mirrorChars.put(0x2A9B, 0x2A9C); // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN
883: mirrorChars.put(0x2A9C, 0x2A9B); // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN
884: mirrorChars.put(0x2AA1, 0x2AA2); // DOUBLE NESTED LESS-THAN
885: mirrorChars.put(0x2AA2, 0x2AA1); // DOUBLE NESTED GREATER-THAN
886: mirrorChars.put(0x2AA6, 0x2AA7); // LESS-THAN CLOSED BY CURVE
887: mirrorChars.put(0x2AA7, 0x2AA6); // GREATER-THAN CLOSED BY CURVE
888: mirrorChars.put(0x2AA8, 0x2AA9); // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
889: mirrorChars.put(0x2AA9, 0x2AA8); // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
890: mirrorChars.put(0x2AAA, 0x2AAB); // SMALLER THAN
891: mirrorChars.put(0x2AAB, 0x2AAA); // LARGER THAN
892: mirrorChars.put(0x2AAC, 0x2AAD); // SMALLER THAN OR EQUAL TO
893: mirrorChars.put(0x2AAD, 0x2AAC); // LARGER THAN OR EQUAL TO
894: mirrorChars.put(0x2AAF, 0x2AB0); // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
895: mirrorChars.put(0x2AB0, 0x2AAF); // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
896: mirrorChars.put(0x2AB3, 0x2AB4); // PRECEDES ABOVE EQUALS SIGN
897: mirrorChars.put(0x2AB4, 0x2AB3); // SUCCEEDS ABOVE EQUALS SIGN
898: mirrorChars.put(0x2ABB, 0x2ABC); // DOUBLE PRECEDES
899: mirrorChars.put(0x2ABC, 0x2ABB); // DOUBLE SUCCEEDS
900: mirrorChars.put(0x2ABD, 0x2ABE); // SUBSET WITH DOT
901: mirrorChars.put(0x2ABE, 0x2ABD); // SUPERSET WITH DOT
902: mirrorChars.put(0x2ABF, 0x2AC0); // SUBSET WITH PLUS SIGN BELOW
903: mirrorChars.put(0x2AC0, 0x2ABF); // SUPERSET WITH PLUS SIGN BELOW
904: mirrorChars.put(0x2AC1, 0x2AC2); // SUBSET WITH MULTIPLICATION SIGN BELOW
905: mirrorChars.put(0x2AC2, 0x2AC1); // SUPERSET WITH MULTIPLICATION SIGN BELOW
906: mirrorChars.put(0x2AC3, 0x2AC4); // SUBSET OF OR EQUAL TO WITH DOT ABOVE
907: mirrorChars.put(0x2AC4, 0x2AC3); // SUPERSET OF OR EQUAL TO WITH DOT ABOVE
908: mirrorChars.put(0x2AC5, 0x2AC6); // SUBSET OF ABOVE EQUALS SIGN
909: mirrorChars.put(0x2AC6, 0x2AC5); // SUPERSET OF ABOVE EQUALS SIGN
910: mirrorChars.put(0x2ACD, 0x2ACE); // SQUARE LEFT OPEN BOX OPERATOR
911: mirrorChars.put(0x2ACE, 0x2ACD); // SQUARE RIGHT OPEN BOX OPERATOR
912: mirrorChars.put(0x2ACF, 0x2AD0); // CLOSED SUBSET
913: mirrorChars.put(0x2AD0, 0x2ACF); // CLOSED SUPERSET
914: mirrorChars.put(0x2AD1, 0x2AD2); // CLOSED SUBSET OR EQUAL TO
915: mirrorChars.put(0x2AD2, 0x2AD1); // CLOSED SUPERSET OR EQUAL TO
916: mirrorChars.put(0x2AD3, 0x2AD4); // SUBSET ABOVE SUPERSET
917: mirrorChars.put(0x2AD4, 0x2AD3); // SUPERSET ABOVE SUBSET
918: mirrorChars.put(0x2AD5, 0x2AD6); // SUBSET ABOVE SUBSET
919: mirrorChars.put(0x2AD6, 0x2AD5); // SUPERSET ABOVE SUPERSET
920: mirrorChars.put(0x2ADE, 0x22A6); // SHORT LEFT TACK
921: mirrorChars.put(0x2AE3, 0x22A9); // DOUBLE VERTICAL BAR LEFT TURNSTILE
922: mirrorChars.put(0x2AE4, 0x22A8); // VERTICAL BAR DOUBLE LEFT TURNSTILE
923: mirrorChars.put(0x2AE5, 0x22AB); // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE
924: mirrorChars.put(0x2AEC, 0x2AED); // DOUBLE STROKE NOT SIGN
925: mirrorChars.put(0x2AED, 0x2AEC); // REVERSED DOUBLE STROKE NOT SIGN
926: mirrorChars.put(0x2AF7, 0x2AF8); // TRIPLE NESTED LESS-THAN
927: mirrorChars.put(0x2AF8, 0x2AF7); // TRIPLE NESTED GREATER-THAN
928: mirrorChars.put(0x2AF9, 0x2AFA); // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO
929: mirrorChars.put(0x2AFA, 0x2AF9); // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO
930: mirrorChars.put(0x3008, 0x3009); // LEFT ANGLE BRACKET
931: mirrorChars.put(0x3009, 0x3008); // RIGHT ANGLE BRACKET
932: mirrorChars.put(0x300A, 0x300B); // LEFT DOUBLE ANGLE BRACKET
933: mirrorChars.put(0x300B, 0x300A); // RIGHT DOUBLE ANGLE BRACKET
934: mirrorChars.put(0x300C, 0x300D); // [BEST FIT] LEFT CORNER BRACKET
935: mirrorChars.put(0x300D, 0x300C); // [BEST FIT] RIGHT CORNER BRACKET
936: mirrorChars.put(0x300E, 0x300F); // [BEST FIT] LEFT WHITE CORNER BRACKET
937: mirrorChars.put(0x300F, 0x300E); // [BEST FIT] RIGHT WHITE CORNER BRACKET
938: mirrorChars.put(0x3010, 0x3011); // LEFT BLACK LENTICULAR BRACKET
939: mirrorChars.put(0x3011, 0x3010); // RIGHT BLACK LENTICULAR BRACKET
940: mirrorChars.put(0x3014, 0x3015); // LEFT TORTOISE SHELL BRACKET
941: mirrorChars.put(0x3015, 0x3014); // RIGHT TORTOISE SHELL BRACKET
942: mirrorChars.put(0x3016, 0x3017); // LEFT WHITE LENTICULAR BRACKET
943: mirrorChars.put(0x3017, 0x3016); // RIGHT WHITE LENTICULAR BRACKET
944: mirrorChars.put(0x3018, 0x3019); // LEFT WHITE TORTOISE SHELL BRACKET
945: mirrorChars.put(0x3019, 0x3018); // RIGHT WHITE TORTOISE SHELL BRACKET
946: mirrorChars.put(0x301A, 0x301B); // LEFT WHITE SQUARE BRACKET
947: mirrorChars.put(0x301B, 0x301A); // RIGHT WHITE SQUARE BRACKET
948: mirrorChars.put(0xFF08, 0xFF09); // FULLWIDTH LEFT PARENTHESIS
949: mirrorChars.put(0xFF09, 0xFF08); // FULLWIDTH RIGHT PARENTHESIS
950: mirrorChars.put(0xFF1C, 0xFF1E); // FULLWIDTH LESS-THAN SIGN
951: mirrorChars.put(0xFF1E, 0xFF1C); // FULLWIDTH GREATER-THAN SIGN
952: mirrorChars.put(0xFF3B, 0xFF3D); // FULLWIDTH LEFT SQUARE BRACKET
953: mirrorChars.put(0xFF3D, 0xFF3B); // FULLWIDTH RIGHT SQUARE BRACKET
954: mirrorChars.put(0xFF5B, 0xFF5D); // FULLWIDTH LEFT CURLY BRACKET
955: mirrorChars.put(0xFF5D, 0xFF5B); // FULLWIDTH RIGHT CURLY BRACKET
956: mirrorChars.put(0xFF5F, 0xFF60); // FULLWIDTH LEFT WHITE PARENTHESIS
957: mirrorChars.put(0xFF60, 0xFF5F); // FULLWIDTH RIGHT WHITE PARENTHESIS
958: mirrorChars.put(0xFF62, 0xFF63); // [BEST FIT] HALFWIDTH LEFT CORNER BRACKET
959: mirrorChars.put(0xFF63, 0xFF62); // [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET
960: }
961: }
|