1 /*
2  * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * (C) Copyright IBM Corp. 2003 - All Rights Reserved
28  *
29  * The original version of this source code and documentation is
30  * copyrighted and owned by IBM. These materials are provided
31  * under terms of a License Agreement between IBM and Sun.
32  * This technology is protected by multiple US and International
33  * patents. This notice and attribution to IBM may not be removed.
34  */
35 
36 package sun.font;
37 
38 import java.text.CharacterIterator;
39 
40 public abstract class CodePointIterator {
41     public static final int DONE = -1;
42 
setToStart()43     public abstract void setToStart();
setToLimit()44     public abstract void setToLimit();
45 
next()46     public abstract int next();
prev()47     public abstract int prev();
48 
charIndex()49     public abstract int charIndex();
50 
create(char[] text)51     public static CodePointIterator create(char[] text) {
52         return new CharArrayCodePointIterator(text);
53     }
54 
create(char[] text, int start, int limit)55     public static CodePointIterator create(char[] text, int start, int limit) {
56         return new CharArrayCodePointIterator(text, start, limit);
57     }
58 
create(CharSequence text)59     public static CodePointIterator create(CharSequence text) {
60         return new CharSequenceCodePointIterator(text);
61     }
62 
create(CharacterIterator iter)63     public static CodePointIterator create(CharacterIterator iter) {
64         return new CharacterIteratorCodePointIterator(iter);
65     }
66 }
67 
68 final class CharArrayCodePointIterator extends CodePointIterator {
69     private char[] text;
70     private int start;
71     private int limit;
72     private int index;
73 
CharArrayCodePointIterator(char[] text)74     public CharArrayCodePointIterator(char[] text) {
75         this.text = text;
76         this.limit = text.length;
77     }
78 
CharArrayCodePointIterator(char[] text, int start, int limit)79     public CharArrayCodePointIterator(char[] text, int start, int limit) {
80         if (start < 0 || limit < start || limit > text.length) {
81             throw new IllegalArgumentException();
82         }
83 
84         this.text = text;
85         this.start = this.index = start;
86         this.limit = limit;
87     }
88 
setToStart()89     public void setToStart() {
90         index = start;
91     }
92 
setToLimit()93     public void setToLimit() {
94         index = limit;
95     }
96 
next()97     public int next() {
98         if (index < limit) {
99             char cp1 = text[index++];
100             if (Character.isHighSurrogate(cp1) && index < limit) {
101                 char cp2 = text[index];
102                 if (Character.isLowSurrogate(cp2)) {
103                     ++index;
104                     return Character.toCodePoint(cp1, cp2);
105                 }
106             }
107             return cp1;
108         }
109         return DONE;
110     }
111 
prev()112     public int prev() {
113         if (index > start) {
114             char cp2 = text[--index];
115             if (Character.isLowSurrogate(cp2) && index > start) {
116                 char cp1 = text[index - 1];
117                 if (Character.isHighSurrogate(cp1)) {
118                     --index;
119                     return Character.toCodePoint(cp1, cp2);
120                 }
121             }
122             return cp2;
123         }
124         return DONE;
125     }
126 
charIndex()127     public int charIndex() {
128         return index;
129     }
130 }
131 
132 final class CharSequenceCodePointIterator extends CodePointIterator {
133     private CharSequence text;
134     private int index;
135 
CharSequenceCodePointIterator(CharSequence text)136     public CharSequenceCodePointIterator(CharSequence text) {
137         this.text = text;
138     }
139 
setToStart()140     public void setToStart() {
141         index = 0;
142     }
143 
setToLimit()144     public void setToLimit() {
145         index = text.length();
146     }
147 
next()148     public int next() {
149         if (index < text.length()) {
150             char cp1 = text.charAt(index++);
151             if (Character.isHighSurrogate(cp1) && index < text.length()) {
152                 char cp2 = text.charAt(index+1);
153                 if (Character.isLowSurrogate(cp2)) {
154                     ++index;
155                     return Character.toCodePoint(cp1, cp2);
156                 }
157             }
158             return cp1;
159         }
160         return DONE;
161     }
162 
prev()163     public int prev() {
164         if (index > 0) {
165             char cp2 = text.charAt(--index);
166             if (Character.isLowSurrogate(cp2) && index > 0) {
167                 char cp1 = text.charAt(index - 1);
168                 if (Character.isHighSurrogate(cp1)) {
169                     --index;
170                     return Character.toCodePoint(cp1, cp2);
171                 }
172             }
173             return cp2;
174         }
175         return DONE;
176     }
177 
charIndex()178     public int charIndex() {
179         return index;
180     }
181 }
182 
183 // note this has different iteration semantics than CharacterIterator
184 final class CharacterIteratorCodePointIterator extends CodePointIterator {
185     private CharacterIterator iter;
186 
CharacterIteratorCodePointIterator(CharacterIterator iter)187     public CharacterIteratorCodePointIterator(CharacterIterator iter) {
188         this.iter = iter;
189     }
190 
setToStart()191     public void setToStart() {
192         iter.setIndex(iter.getBeginIndex());
193     }
194 
setToLimit()195     public void setToLimit() {
196         iter.setIndex(iter.getEndIndex());
197     }
198 
next()199     public int next() {
200         char cp1 = iter.current();
201         if (cp1 != CharacterIterator.DONE) {
202             char cp2 = iter.next();
203             if (Character.isHighSurrogate(cp1) && cp2 != CharacterIterator.DONE) {
204                 if (Character.isLowSurrogate(cp2)) {
205                     iter.next();
206                     return Character.toCodePoint(cp1, cp2);
207                 }
208             }
209             return cp1;
210         }
211         return DONE;
212     }
213 
prev()214     public int prev() {
215         char cp2 = iter.previous();
216         if (cp2 != CharacterIterator.DONE) {
217             if (Character.isLowSurrogate(cp2)) {
218                 char cp1 = iter.previous();
219                 if (Character.isHighSurrogate(cp1)) {
220                     return Character.toCodePoint(cp1, cp2);
221                 }
222                 iter.next();
223             }
224             return cp2;
225         }
226         return DONE;
227     }
228 
charIndex()229     public int charIndex() {
230         return iter.getIndex();
231     }
232 }
233