History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/font/StyledParagraph.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/font/StyledParagraph.java+492−0
@@ -0,0 +1,492 @@
1+/*
2+ * Copyright (c) 1999, 2005, 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+/*
28+ * (C) Copyright IBM Corp. 1999, All rights reserved.
29+ */
30+package java.awt.font;
31+
32+import java.awt.Font;
33+import java.awt.Toolkit;
34+import java.awt.im.InputMethodHighlight;
35+import java.text.Annotation;
36+import java.text.AttributedCharacterIterator;
37+import java.util.Vector;
38+import java.util.HashMap;
39+import java.util.Map;
40+import sun.font.Decoration;
41+import sun.font.FontResolver;
42+import sun.text.CodePointIterator;
43+
44+/**
45+ * This class stores Font, GraphicAttribute, and Decoration intervals
46+ * on a paragraph of styled text.
47+ * <p>
48+ * Currently, this class is optimized for a small number of intervals
49+ * (preferrably 1).
50+ */
51+final class StyledParagraph {
52+
53+ // the length of the paragraph
54+ private int length;
55+
56+ // If there is a single Decoration for the whole paragraph, it
57+ // is stored here. Otherwise this field is ignored.
58+
59+ private Decoration decoration;
60+
61+ // If there is a single Font or GraphicAttribute for the whole
62+ // paragraph, it is stored here. Otherwise this field is ignored.
63+ private Object font;
64+
65+ // If there are multiple Decorations in the paragraph, they are
66+ // stored in this Vector, in order. Otherwise this vector and
67+ // the decorationStarts array are null.
68+ private Vector decorations;
69+ // If there are multiple Decorations in the paragraph,
70+ // decorationStarts[i] contains the index where decoration i
71+ // starts. For convenience, there is an extra entry at the
72+ // end of this array with the length of the paragraph.
73+ int[] decorationStarts;
74+
75+ // If there are multiple Fonts/GraphicAttributes in the paragraph,
76+ // they are
77+ // stored in this Vector, in order. Otherwise this vector and
78+ // the fontStarts array are null.
79+ private Vector fonts;
80+ // If there are multiple Fonts/GraphicAttributes in the paragraph,
81+ // fontStarts[i] contains the index where decoration i
82+ // starts. For convenience, there is an extra entry at the
83+ // end of this array with the length of the paragraph.
84+ int[] fontStarts;
85+
86+ private static int INITIAL_SIZE = 8;
87+
88+ /**
89+ * Create a new StyledParagraph over the given styled text.
90+ * @param aci an iterator over the text
91+ * @param chars the characters extracted from aci
92+ */
93+ public StyledParagraph(AttributedCharacterIterator aci,
94+ char[] chars) {
95+
96+ int start = aci.getBeginIndex();
97+ int end = aci.getEndIndex();
98+ length = end - start;
99+
100+ int index = start;
101+ aci.first();
102+
103+ do {
104+ final int nextRunStart = aci.getRunLimit();
105+ final int localIndex = index-start;
106+
107+ Map attributes = aci.getAttributes();
108+ attributes = addInputMethodAttrs(attributes);
109+ Decoration d = Decoration.getDecoration(attributes);
110+ addDecoration(d, localIndex);
111+
112+ Object f = getGraphicOrFont(attributes);
113+ if (f == null) {
114+ addFonts(chars, attributes, localIndex, nextRunStart-start);
115+ }
116+ else {
117+ addFont(f, localIndex);
118+ }
119+
120+ aci.setIndex(nextRunStart);
121+ index = nextRunStart;
122+
123+ } while (index < end);
124+
125+ // Add extra entries to starts arrays with the length
126+ // of the paragraph. 'this' is used as a dummy value
127+ // in the Vector.
128+ if (decorations != null) {
129+ decorationStarts = addToVector(this, length, decorations, decorationStarts);
130+ }
131+ if (fonts != null) {
132+ fontStarts = addToVector(this, length, fonts, fontStarts);
133+ }
134+ }
135+
136+ /**
137+ * Adjust indices in starts to reflect an insertion after pos.
138+ * Any index in starts greater than pos will be increased by 1.
139+ */
140+ private static void insertInto(int pos, int[] starts, int numStarts) {
141+
142+ while (starts[--numStarts] > pos) {
143+ starts[numStarts] += 1;
144+ }
145+ }
146+
147+ /**
148+ * Return a StyledParagraph reflecting the insertion of a single character
149+ * into the text. This method will attempt to reuse the given paragraph,
150+ * but may create a new paragraph.
151+ * @param aci an iterator over the text. The text should be the same as the
152+ * text used to create (or most recently update) oldParagraph, with
153+ * the exception of inserting a single character at insertPos.
154+ * @param chars the characters in aci
155+ * @param insertPos the index of the new character in aci
156+ * @param oldParagraph a StyledParagraph for the text in aci before the
157+ * insertion
158+ */
159+ public static StyledParagraph insertChar(AttributedCharacterIterator aci,
160+ char[] chars,
161+ int insertPos,
162+ StyledParagraph oldParagraph) {
163+
164+ // If the styles at insertPos match those at insertPos-1,
165+ // oldParagraph will be reused. Otherwise we create a new
166+ // paragraph.
167+
168+ char ch = aci.setIndex(insertPos);
169+ int relativePos = Math.max(insertPos - aci.getBeginIndex() - 1, 0);
170+
171+ Map attributes = addInputMethodAttrs(aci.getAttributes());
172+ Decoration d = Decoration.getDecoration(attributes);
173+ if (!oldParagraph.getDecorationAt(relativePos).equals(d)) {
174+ return new StyledParagraph(aci, chars);
175+ }
176+ Object f = getGraphicOrFont(attributes);
177+ if (f == null) {
178+ FontResolver resolver = FontResolver.getInstance();
179+ int fontIndex = resolver.getFontIndex(ch);
180+ f = resolver.getFont(fontIndex, attributes);
181+ }
182+ if (!oldParagraph.getFontOrGraphicAt(relativePos).equals(f)) {
183+ return new StyledParagraph(aci, chars);
184+ }
185+
186+ // insert into existing paragraph
187+ oldParagraph.length += 1;
188+ if (oldParagraph.decorations != null) {
189+ insertInto(relativePos,
190+ oldParagraph.decorationStarts,
191+ oldParagraph.decorations.size());
192+ }
193+ if (oldParagraph.fonts != null) {
194+ insertInto(relativePos,
195+ oldParagraph.fontStarts,
196+ oldParagraph.fonts.size());
197+ }
198+ return oldParagraph;
199+ }
200+
201+ /**
202+ * Adjust indices in starts to reflect a deletion after deleteAt.
203+ * Any index in starts greater than deleteAt will be increased by 1.
204+ * It is the caller's responsibility to make sure that no 0-length
205+ * runs result.
206+ */
207+ private static void deleteFrom(int deleteAt, int[] starts, int numStarts) {
208+
209+ while (starts[--numStarts] > deleteAt) {
210+ starts[numStarts] -= 1;
211+ }
212+ }
213+
214+ /**
215+ * Return a StyledParagraph reflecting the insertion of a single character
216+ * into the text. This method will attempt to reuse the given paragraph,
217+ * but may create a new paragraph.
218+ * @param aci an iterator over the text. The text should be the same as the
219+ * text used to create (or most recently update) oldParagraph, with
220+ * the exception of deleting a single character at deletePos.
221+ * @param chars the characters in aci
222+ * @param deletePos the index where a character was removed
223+ * @param oldParagraph a StyledParagraph for the text in aci before the
224+ * insertion
225+ */
226+ public static StyledParagraph deleteChar(AttributedCharacterIterator aci,
227+ char[] chars,
228+ int deletePos,
229+ StyledParagraph oldParagraph) {
230+
231+ // We will reuse oldParagraph unless there was a length-1 run
232+ // at deletePos. We could do more work and check the individual
233+ // Font and Decoration runs, but we don't right now...
234+ deletePos -= aci.getBeginIndex();
235+
236+ if (oldParagraph.decorations == null && oldParagraph.fonts == null) {
237+ oldParagraph.length -= 1;
238+ return oldParagraph;
239+ }
240+
241+ if (oldParagraph.getRunLimit(deletePos) == deletePos+1) {
242+ if (deletePos == 0 || oldParagraph.getRunLimit(deletePos-1) == deletePos) {
243+ return new StyledParagraph(aci, chars);
244+ }
245+ }
246+
247+ oldParagraph.length -= 1;
248+ if (oldParagraph.decorations != null) {
249+ deleteFrom(deletePos,
250+ oldParagraph.decorationStarts,
251+ oldParagraph.decorations.size());
252+ }
253+ if (oldParagraph.fonts != null) {
254+ deleteFrom(deletePos,
255+ oldParagraph.fontStarts,
256+ oldParagraph.fonts.size());
257+ }
258+ return oldParagraph;
259+ }
260+
261+ /**
262+ * Return the index at which there is a different Font, GraphicAttribute, or
263+ * Dcoration than at the given index.
264+ * @param index a valid index in the paragraph
265+ * @return the first index where there is a change in attributes from
266+ * those at index
267+ */
268+ public int getRunLimit(int index) {
269+
270+ if (index < 0 || index >= length) {
271+ throw new IllegalArgumentException("index out of range");
272+ }
273+ int limit1 = length;
274+ if (decorations != null) {
275+ int run = findRunContaining(index, decorationStarts);
276+ limit1 = decorationStarts[run+1];
277+ }
278+ int limit2 = length;
279+ if (fonts != null) {
280+ int run = findRunContaining(index, fontStarts);
281+ limit2 = fontStarts[run+1];
282+ }
283+ return Math.min(limit1, limit2);
284+ }
285+
286+ /**
287+ * Return the Decoration in effect at the given index.
288+ * @param index a valid index in the paragraph
289+ * @return the Decoration at index.
290+ */
291+ public Decoration getDecorationAt(int index) {
292+
293+ if (index < 0 || index >= length) {
294+ throw new IllegalArgumentException("index out of range");
295+ }
296+ if (decorations == null) {
297+ return decoration;
298+ }
299+ int run = findRunContaining(index, decorationStarts);
300+ return (Decoration) decorations.elementAt(run);
301+ }
302+
303+ /**
304+ * Return the Font or GraphicAttribute in effect at the given index.
305+ * The client must test the type of the return value to determine what
306+ * it is.
307+ * @param index a valid index in the paragraph
308+ * @return the Font or GraphicAttribute at index.
309+ */
310+ public Object getFontOrGraphicAt(int index) {
311+
312+ if (index < 0 || index >= length) {
313+ throw new IllegalArgumentException("index out of range");
314+ }
315+ if (fonts == null) {
316+ return font;
317+ }
318+ int run = findRunContaining(index, fontStarts);
319+ return fonts.elementAt(run);
320+ }
321+
322+ /**
323+ * Return i such that starts[i] <= index < starts[i+1]. starts
324+ * must be in increasing order, with at least one element greater
325+ * than index.
326+ */
327+ private static int findRunContaining(int index, int[] starts) {
328+
329+ for (int i=1; true; i++) {
330+ if (starts[i] > index) {
331+ return i-1;
332+ }
333+ }
334+ }
335+
336+ /**
337+ * Append the given Object to the given Vector. Add
338+ * the given index to the given starts array. If the
339+ * starts array does not have room for the index, a
340+ * new array is created and returned.
341+ */
342+ private static int[] addToVector(Object obj,
343+ int index,
344+ Vector v,
345+ int[] starts) {
346+
347+ if (!v.lastElement().equals(obj)) {
348+ v.addElement(obj);
349+ int count = v.size();
350+ if (starts.length == count) {
351+ int[] temp = new int[starts.length*2];
352+ System.arraycopy(starts, 0, temp, 0, starts.length);
353+ starts = temp;
354+ }
355+ starts[count-1] = index;
356+ }
357+ return starts;
358+ }
359+
360+ /**
361+ * Add a new Decoration run with the given Decoration at the
362+ * given index.
363+ */
364+ private void addDecoration(Decoration d, int index) {
365+
366+ if (decorations != null) {
367+ decorationStarts = addToVector(d,
368+ index,
369+ decorations,
370+ decorationStarts);
371+ }
372+ else if (decoration == null) {
373+ decoration = d;
374+ }
375+ else {
376+ if (!decoration.equals(d)) {
377+ decorations = new Vector(INITIAL_SIZE);
378+ decorations.addElement(decoration);
379+ decorations.addElement(d);
380+ decorationStarts = new int[INITIAL_SIZE];
381+ decorationStarts[0] = 0;
382+ decorationStarts[1] = index;
383+ }
384+ }
385+ }
386+
387+ /**
388+ * Add a new Font/GraphicAttribute run with the given object at the
389+ * given index.
390+ */
391+ private void addFont(Object f, int index) {
392+
393+ if (fonts != null) {
394+ fontStarts = addToVector(f, index, fonts, fontStarts);
395+ }
396+ else if (font == null) {
397+ font = f;
398+ }
399+ else {
400+ if (!font.equals(f)) {
401+ fonts = new Vector(INITIAL_SIZE);
402+ fonts.addElement(font);
403+ fonts.addElement(f);
404+ fontStarts = new int[INITIAL_SIZE];
405+ fontStarts[0] = 0;
406+ fontStarts[1] = index;
407+ }
408+ }
409+ }
410+
411+ /**
412+ * Resolve the given chars into Fonts using FontResolver, then add
413+ * font runs for each.
414+ */
415+ private void addFonts(char[] chars, Map attributes, int start, int limit) {
416+
417+ FontResolver resolver = FontResolver.getInstance();
418+ CodePointIterator iter = CodePointIterator.create(chars, start, limit);
419+ for (int runStart = iter.charIndex(); runStart < limit; runStart = iter.charIndex()) {
420+ int fontIndex = resolver.nextFontRunIndex(iter);
421+ addFont(resolver.getFont(fontIndex, attributes), runStart);
422+ }
423+ }
424+
425+ /**
426+ * Return a Map with entries from oldStyles, as well as input
427+ * method entries, if any.
428+ */
429+ static Map addInputMethodAttrs(Map oldStyles) {
430+
431+ Object value = oldStyles.get(TextAttribute.INPUT_METHOD_HIGHLIGHT);
432+
433+ try {
434+ if (value != null) {
435+ if (value instanceof Annotation) {
436+ value = ((Annotation)value).getValue();
437+ }
438+
439+ InputMethodHighlight hl;
440+ hl = (InputMethodHighlight) value;
441+
442+ Map imStyles = null;
443+ try {
444+ imStyles = hl.getStyle();
445+ } catch (NoSuchMethodError e) {
446+ }
447+
448+ if (imStyles == null) {
449+ Toolkit tk = Toolkit.getDefaultToolkit();
450+ imStyles = tk.mapInputMethodHighlight(hl);
451+ }
452+
453+ if (imStyles != null) {
454+ HashMap newStyles = new HashMap(5, (float)0.9);
455+ newStyles.putAll(oldStyles);
456+
457+ newStyles.putAll(imStyles);
458+
459+ return newStyles;
460+ }
461+ }
462+ }
463+ catch(ClassCastException e) {
464+ }
465+
466+ return oldStyles;
467+ }
468+
469+ /**
470+ * Extract a GraphicAttribute or Font from the given attributes.
471+ * If attributes does not contain a GraphicAttribute, Font, or
472+ * Font family entry this method returns null.
473+ */
474+ private static Object getGraphicOrFont(Map attributes) {
475+
476+ Object value = attributes.get(TextAttribute.CHAR_REPLACEMENT);
477+ if (value != null) {
478+ return value;
479+ }
480+ value = attributes.get(TextAttribute.FONT);
481+ if (value != null) {
482+ return value;
483+ }
484+
485+ if (attributes.get(TextAttribute.FAMILY) != null) {
486+ return Font.getFont(attributes);
487+ }
488+ else {
489+ return null;
490+ }
491+ }
492+}