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/javax/swing/text/html/Map.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/text/html/Map.java+503−0
@@ -0,0 +1,503 @@
1+/*
2+ * Copyright (c) 1998, 2008, 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+package javax.swing.text.html;
26+
27+import java.awt.Polygon;
28+import java.io.Serializable;
29+import java.util.StringTokenizer;
30+import java.util.Vector;
31+import javax.swing.text.AttributeSet;
32+
33+/**
34+ * Map is used to represent a map element that is part of an HTML document.
35+ * Once a Map has been created, and any number of areas have been added,
36+ * you can test if a point falls inside the map via the contains method.
37+ *
38+ * @author Scott Violet
39+ */
40+class Map implements Serializable {
41+ /** Name of the Map. */
42+ private String name;
43+ /** An array of AttributeSets. */
44+ private Vector<AttributeSet> areaAttributes;
45+ /** An array of RegionContainments, will slowly grow to match the
46+ * length of areaAttributes as needed. */
47+ private Vector<RegionContainment> areas;
48+
49+ public Map() {
50+ }
51+
52+ public Map(String name) {
53+ this.name = name;
54+ }
55+
56+ /**
57+ * Returns the name of the Map.
58+ */
59+ public String getName() {
60+ return name;
61+ }
62+
63+ /**
64+ * Defines a region of the Map, based on the passed in AttributeSet.
65+ */
66+ public void addArea(AttributeSet as) {
67+ if (as == null) {
68+ return;
69+ }
70+ if (areaAttributes == null) {
71+ areaAttributes = new Vector<AttributeSet>(2);
72+ }
73+ areaAttributes.addElement(as.copyAttributes());
74+ }
75+
76+ /**
77+ * Removes the previously created area.
78+ */
79+ public void removeArea(AttributeSet as) {
80+ if (as != null && areaAttributes != null) {
81+ int numAreas = (areas != null) ? areas.size() : 0;
82+ for (int counter = areaAttributes.size() - 1; counter >= 0;
83+ counter--) {
84+ if (areaAttributes.elementAt(counter).isEqual(as)){
85+ areaAttributes.removeElementAt(counter);
86+ if (counter < numAreas) {
87+ areas.removeElementAt(counter);
88+ }
89+ }
90+ }
91+ }
92+ }
93+
94+ /**
95+ * Returns the AttributeSets representing the differet areas of the Map.
96+ */
97+ public AttributeSet[] getAreas() {
98+ int numAttributes = (areaAttributes != null) ? areaAttributes.size() :
99+ 0;
100+ if (numAttributes != 0) {
101+ AttributeSet[] retValue = new AttributeSet[numAttributes];
102+
103+ areaAttributes.copyInto(retValue);
104+ return retValue;
105+ }
106+ return null;
107+ }
108+
109+ /**
110+ * Returns the AttributeSet that contains the passed in location,
111+ * <code>x</code>, <code>y</code>. <code>width</code>, <code>height</code>
112+ * gives the size of the region the map is defined over. If a matching
113+ * area is found, the AttribueSet for it is returned.
114+ */
115+ public AttributeSet getArea(int x, int y, int width, int height) {
116+ int numAttributes = (areaAttributes != null) ?
117+ areaAttributes.size() : 0;
118+
119+ if (numAttributes > 0) {
120+ int numAreas = (areas != null) ? areas.size() : 0;
121+
122+ if (areas == null) {
123+ areas = new Vector<RegionContainment>(numAttributes);
124+ }
125+ for (int counter = 0; counter < numAttributes; counter++) {
126+ if (counter >= numAreas) {
127+ areas.addElement(createRegionContainment
128+ (areaAttributes.elementAt(counter)));
129+ }
130+ RegionContainment rc = areas.elementAt(counter);
131+ if (rc != null && rc.contains(x, y, width, height)) {
132+ return areaAttributes.elementAt(counter);
133+ }
134+ }
135+ }
136+ return null;
137+ }
138+
139+ /**
140+ * Creates and returns an instance of RegionContainment that can be
141+ * used to test if a particular point lies inside a region.
142+ */
143+ protected RegionContainment createRegionContainment
144+ (AttributeSet attributes) {
145+ Object shape = attributes.getAttribute(HTML.Attribute.SHAPE);
146+
147+ if (shape == null) {
148+ shape = "rect";
149+ }
150+ if (shape instanceof String) {
151+ String shapeString = ((String)shape).toLowerCase();
152+ RegionContainment rc = null;
153+
154+ try {
155+ if (shapeString.equals("rect")) {
156+ rc = new RectangleRegionContainment(attributes);
157+ }
158+ else if (shapeString.equals("circle")) {
159+ rc = new CircleRegionContainment(attributes);
160+ }
161+ else if (shapeString.equals("poly")) {
162+ rc = new PolygonRegionContainment(attributes);
163+ }
164+ else if (shapeString.equals("default")) {
165+ rc = DefaultRegionContainment.sharedInstance();
166+ }
167+ } catch (RuntimeException re) {
168+ // Something wrong with attributes.
169+ rc = null;
170+ }
171+ return rc;
172+ }
173+ return null;
174+ }
175+
176+ /**
177+ * Creates and returns an array of integers from the String
178+ * <code>stringCoords</code>. If one of the values represents a
179+ * % the returned value with be negative. If a parse error results
180+ * from trying to parse one of the numbers null is returned.
181+ */
182+ static protected int[] extractCoords(Object stringCoords) {
183+ if (stringCoords == null || !(stringCoords instanceof String)) {
184+ return null;
185+ }
186+
187+ StringTokenizer st = new StringTokenizer((String)stringCoords,
188+ ", \t\n\r");
189+ int[] retValue = null;
190+ int numCoords = 0;
191+
192+ while(st.hasMoreElements()) {
193+ String token = st.nextToken();
194+ int scale;
195+
196+ if (token.endsWith("%")) {
197+ scale = -1;
198+ token = token.substring(0, token.length() - 1);
199+ }
200+ else {
201+ scale = 1;
202+ }
203+ try {
204+ int intValue = Integer.parseInt(token);
205+
206+ if (retValue == null) {
207+ retValue = new int[4];
208+ }
209+ else if(numCoords == retValue.length) {
210+ int[] temp = new int[retValue.length * 2];
211+
212+ System.arraycopy(retValue, 0, temp, 0, retValue.length);
213+ retValue = temp;
214+ }
215+ retValue[numCoords++] = intValue * scale;
216+ } catch (NumberFormatException nfe) {
217+ return null;
218+ }
219+ }
220+ if (numCoords > 0 && numCoords != retValue.length) {
221+ int[] temp = new int[numCoords];
222+
223+ System.arraycopy(retValue, 0, temp, 0, numCoords);
224+ retValue = temp;
225+ }
226+ return retValue;
227+ }
228+
229+
230+ /**
231+ * Defines the interface used for to check if a point is inside a
232+ * region.
233+ */
234+ interface RegionContainment {
235+ /**
236+ * Returns true if the location <code>x</code>, <code>y</code>
237+ * falls inside the region defined in the receiver.
238+ * <code>width</code>, <code>height</code> is the size of
239+ * the enclosing region.
240+ */
241+ public boolean contains(int x, int y, int width, int height);
242+ }
243+
244+
245+ /**
246+ * Used to test for containment in a rectangular region.
247+ */
248+ static class RectangleRegionContainment implements RegionContainment {
249+ /** Will be non-null if one of the values is a percent, and any value
250+ * that is non null indicates it is a percent
251+ * (order is x, y, width, height). */
252+ float[] percents;
253+ /** Last value of width passed in. */
254+ int lastWidth;
255+ /** Last value of height passed in. */
256+ int lastHeight;
257+ /** Top left. */
258+ int x0;
259+ int y0;
260+ /** Bottom right. */
261+ int x1;
262+ int y1;
263+
264+ public RectangleRegionContainment(AttributeSet as) {
265+ int[] coords = Map.extractCoords(as.getAttribute(HTML.
266+ Attribute.COORDS));
267+
268+ percents = null;
269+ if (coords == null || coords.length != 4) {
270+ throw new RuntimeException("Unable to parse rectangular area");
271+ }
272+ else {
273+ x0 = coords[0];
274+ y0 = coords[1];
275+ x1 = coords[2];
276+ y1 = coords[3];
277+ if (x0 < 0 || y0 < 0 || x1 < 0 || y1 < 0) {
278+ percents = new float[4];
279+ lastWidth = lastHeight = -1;
280+ for (int counter = 0; counter < 4; counter++) {
281+ if (coords[counter] < 0) {
282+ percents[counter] = Math.abs
283+ (coords[counter]) / 100.0f;
284+ }
285+ else {
286+ percents[counter] = -1.0f;
287+ }
288+ }
289+ }
290+ }
291+ }
292+
293+ public boolean contains(int x, int y, int width, int height) {
294+ if (percents == null) {
295+ return contains(x, y);
296+ }
297+ if (lastWidth != width || lastHeight != height) {
298+ lastWidth = width;
299+ lastHeight = height;
300+ if (percents[0] != -1.0f) {
301+ x0 = (int)(percents[0] * width);
302+ }
303+ if (percents[1] != -1.0f) {
304+ y0 = (int)(percents[1] * height);
305+ }
306+ if (percents[2] != -1.0f) {
307+ x1 = (int)(percents[2] * width);
308+ }
309+ if (percents[3] != -1.0f) {
310+ y1 = (int)(percents[3] * height);
311+ }
312+ }
313+ return contains(x, y);
314+ }
315+
316+ public boolean contains(int x, int y) {
317+ return ((x >= x0 && x <= x1) &&
318+ (y >= y0 && y <= y1));
319+ }
320+ }
321+
322+
323+ /**
324+ * Used to test for containment in a polygon region.
325+ */
326+ static class PolygonRegionContainment extends Polygon implements
327+ RegionContainment {
328+ /** If any value is a percent there will be an entry here for the
329+ * percent value. Use percentIndex to find out the index for it. */
330+ float[] percentValues;
331+ int[] percentIndexs;
332+ /** Last value of width passed in. */
333+ int lastWidth;
334+ /** Last value of height passed in. */
335+ int lastHeight;
336+
337+ public PolygonRegionContainment(AttributeSet as) {
338+ int[] coords = Map.extractCoords(as.getAttribute(HTML.Attribute.
339+ COORDS));
340+
341+ if (coords == null || coords.length == 0 ||
342+ coords.length % 2 != 0) {
343+ throw new RuntimeException("Unable to parse polygon area");
344+ }
345+ else {
346+ int numPercents = 0;
347+
348+ lastWidth = lastHeight = -1;
349+ for (int counter = coords.length - 1; counter >= 0;
350+ counter--) {
351+ if (coords[counter] < 0) {
352+ numPercents++;
353+ }
354+ }
355+
356+ if (numPercents > 0) {
357+ percentIndexs = new int[numPercents];
358+ percentValues = new float[numPercents];
359+ for (int counter = coords.length - 1, pCounter = 0;
360+ counter >= 0; counter--) {
361+ if (coords[counter] < 0) {
362+ percentValues[pCounter] = coords[counter] /
363+ -100.0f;
364+ percentIndexs[pCounter] = counter;
365+ pCounter++;
366+ }
367+ }
368+ }
369+ else {
370+ percentIndexs = null;
371+ percentValues = null;
372+ }
373+ npoints = coords.length / 2;
374+ xpoints = new int[npoints];
375+ ypoints = new int[npoints];
376+
377+ for (int counter = 0; counter < npoints; counter++) {
378+ xpoints[counter] = coords[counter + counter];
379+ ypoints[counter] = coords[counter + counter + 1];
380+ }
381+ }
382+ }
383+
384+ public boolean contains(int x, int y, int width, int height) {
385+ if (percentValues == null || (lastWidth == width &&
386+ lastHeight == height)) {
387+ return contains(x, y);
388+ }
389+ // Force the bounding box to be recalced.
390+ bounds = null;
391+ lastWidth = width;
392+ lastHeight = height;
393+ float fWidth = (float)width;
394+ float fHeight = (float)height;
395+ for (int counter = percentValues.length - 1; counter >= 0;
396+ counter--) {
397+ if (percentIndexs[counter] % 2 == 0) {
398+ // x
399+ xpoints[percentIndexs[counter] / 2] =
400+ (int)(percentValues[counter] * fWidth);
401+ }
402+ else {
403+ // y
404+ ypoints[percentIndexs[counter] / 2] =
405+ (int)(percentValues[counter] * fHeight);
406+ }
407+ }
408+ return contains(x, y);
409+ }
410+ }
411+
412+
413+ /**
414+ * Used to test for containment in a circular region.
415+ */
416+ static class CircleRegionContainment implements RegionContainment {
417+ /** X origin of the circle. */
418+ int x;
419+ /** Y origin of the circle. */
420+ int y;
421+ /** Radius of the circle. */
422+ int radiusSquared;
423+ /** Non-null indicates one of the values represents a percent. */
424+ float[] percentValues;
425+ /** Last value of width passed in. */
426+ int lastWidth;
427+ /** Last value of height passed in. */
428+ int lastHeight;
429+
430+ public CircleRegionContainment(AttributeSet as) {
431+ int[] coords = Map.extractCoords(as.getAttribute(HTML.Attribute.
432+ COORDS));
433+
434+ if (coords == null || coords.length != 3) {
435+ throw new RuntimeException("Unable to parse circular area");
436+ }
437+ x = coords[0];
438+ y = coords[1];
439+ radiusSquared = coords[2] * coords[2];
440+ if (coords[0] < 0 || coords[1] < 0 || coords[2] < 0) {
441+ lastWidth = lastHeight = -1;
442+ percentValues = new float[3];
443+ for (int counter = 0; counter < 3; counter++) {
444+ if (coords[counter] < 0) {
445+ percentValues[counter] = coords[counter] /
446+ -100.0f;
447+ }
448+ else {
449+ percentValues[counter] = -1.0f;
450+ }
451+ }
452+ }
453+ else {
454+ percentValues = null;
455+ }
456+ }
457+
458+ public boolean contains(int x, int y, int width, int height) {
459+ if (percentValues != null && (lastWidth != width ||
460+ lastHeight != height)) {
461+ int newRad = Math.min(width, height) / 2;
462+
463+ lastWidth = width;
464+ lastHeight = height;
465+ if (percentValues[0] != -1.0f) {
466+ this.x = (int)(percentValues[0] * width);
467+ }
468+ if (percentValues[1] != -1.0f) {
469+ this.y = (int)(percentValues[1] * height);
470+ }
471+ if (percentValues[2] != -1.0f) {
472+ radiusSquared = (int)(percentValues[2] *
473+ Math.min(width, height));
474+ radiusSquared *= radiusSquared;
475+ }
476+ }
477+ return (((x - this.x) * (x - this.x) +
478+ (y - this.y) * (y - this.y)) <= radiusSquared);
479+ }
480+ }
481+
482+
483+ /**
484+ * An implementation that will return true if the x, y location is
485+ * inside a rectangle defined by origin 0, 0, and width equal to
486+ * width passed in, and height equal to height passed in.
487+ */
488+ static class DefaultRegionContainment implements RegionContainment {
489+ /** A global shared instance. */
490+ static DefaultRegionContainment si = null;
491+
492+ public static DefaultRegionContainment sharedInstance() {
493+ if (si == null) {
494+ si = new DefaultRegionContainment();
495+ }
496+ return si;
497+ }
498+
499+ public boolean contains(int x, int y, int width, int height) {
500+ return (x <= width && x >= 0 && y >= 0 && y <= width);
501+ }
502+ }
503+}