Source Code Cross Referenced for CaretManager.java in  » Apache-Harmony-Java-SE » org-package » org » apache » harmony » awt » gl » font » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Apache Harmony Java SE » org package » org.apache.harmony.awt.gl.font 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
003:         *  contributor license agreements.  See the NOTICE file distributed with
004:         *  this work for additional information regarding copyright ownership.
005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
006:         *  (the "License"); you may not use this file except in compliance with
007:         *  the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         *  Unless required by applicable law or agreed to in writing, software
012:         *  distributed under the License is distributed on an "AS IS" BASIS,
013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         *  See the License for the specific language governing permissions and
015:         *  limitations under the License.
016:         */
017:        /**
018:         * @author Oleg V. Khaschansky
019:         * @version $Revision$
020:         *
021:         * @date: Jun 14, 2005
022:         */package org.apache.harmony.awt.gl.font;
023:
024:        import java.awt.font.TextHitInfo;
025:        import java.awt.font.TextLayout;
026:        import java.awt.geom.Rectangle2D;
027:        import java.awt.geom.GeneralPath;
028:        import java.awt.geom.Line2D;
029:        import java.awt.*;
030:
031:        import org.apache.harmony.awt.internal.nls.Messages;
032:
033:        /**
034:         * This class provides functionality for creating caret and highlight shapes
035:         * (bidirectional text is also supported, but, unfortunately, not tested yet).
036:         */
037:        public class CaretManager {
038:            private TextRunBreaker breaker;
039:
040:            public CaretManager(TextRunBreaker breaker) {
041:                this .breaker = breaker;
042:            }
043:
044:            /**
045:             * Checks if TextHitInfo is not out of the text range and throws the
046:             * IllegalArgumentException if it is.
047:             * @param info - text hit info
048:             */
049:            private void checkHit(TextHitInfo info) {
050:                int idx = info.getInsertionIndex();
051:
052:                if (idx < 0 || idx > breaker.getCharCount()) {
053:                    // awt.42=TextHitInfo out of range
054:                    throw new IllegalArgumentException(Messages
055:                            .getString("awt.42")); //$NON-NLS-1$
056:                }
057:            }
058:
059:            /**
060:             * Calculates and returns visual position from the text hit info.
061:             * @param hitInfo - text hit info
062:             * @return visual index
063:             */
064:            private int getVisualFromHitInfo(TextHitInfo hitInfo) {
065:                final int idx = hitInfo.getCharIndex();
066:
067:                if (idx >= 0 && idx < breaker.getCharCount()) {
068:                    int visual = breaker.getVisualFromLogical(idx);
069:                    // We take next character for (LTR char + TRAILING info) and (RTL + LEADING)
070:                    if (hitInfo.isLeadingEdge()
071:                            ^ ((breaker.getLevel(idx) & 0x1) == 0x0)) {
072:                        visual++;
073:                    }
074:                    return visual;
075:                } else if (idx < 0) {
076:                    return breaker.isLTR() ? 0 : breaker.getCharCount();
077:                } else {
078:                    return breaker.isLTR() ? breaker.getCharCount() : 0;
079:                }
080:            }
081:
082:            /**
083:             * Calculates text hit info from the visual position
084:             * @param visual - visual position
085:             * @return text hit info
086:             */
087:            private TextHitInfo getHitInfoFromVisual(int visual) {
088:                final boolean first = visual == 0;
089:
090:                if (!(first || visual == breaker.getCharCount())) {
091:                    int logical = breaker.getLogicalFromVisual(visual);
092:                    return (breaker.getLevel(logical) & 0x1) == 0x0 ? TextHitInfo
093:                            .leading(logical)
094:                            : // LTR
095:                            TextHitInfo.trailing(logical); // RTL
096:                } else if (first) {
097:                    return breaker.isLTR() ? TextHitInfo.trailing(-1)
098:                            : TextHitInfo.leading(breaker.getCharCount());
099:                } else { // Last
100:                    return breaker.isLTR() ? TextHitInfo.leading(breaker
101:                            .getCharCount()) : TextHitInfo.trailing(-1);
102:                }
103:            }
104:
105:            /**
106:             * Creates caret info. Required for the getCaretInfo
107:             * methods of the TextLayout
108:             * @param hitInfo - specifies caret position
109:             * @return caret info, see TextLayout.getCaretInfo documentation
110:             */
111:            public float[] getCaretInfo(TextHitInfo hitInfo) {
112:                checkHit(hitInfo);
113:                float res[] = new float[2];
114:
115:                int visual = getVisualFromHitInfo(hitInfo);
116:                float advance, angle;
117:                TextRunSegment seg;
118:
119:                if (visual < breaker.getCharCount()) {
120:                    int logIdx = breaker.getLogicalFromVisual(visual);
121:                    int segmentIdx = breaker.logical2segment[logIdx];
122:                    seg = breaker.runSegments.get(segmentIdx);
123:                    advance = seg.x
124:                            + seg.getAdvanceDelta(seg.getStart(), logIdx);
125:                    angle = seg.metrics.italicAngle;
126:
127:                } else { // Last character
128:                    int logIdx = breaker.getLogicalFromVisual(visual - 1);
129:                    int segmentIdx = breaker.logical2segment[logIdx];
130:                    seg = breaker.runSegments.get(segmentIdx);
131:                    advance = seg.x
132:                            + seg.getAdvanceDelta(seg.getStart(), logIdx + 1);
133:                }
134:
135:                angle = seg.metrics.italicAngle;
136:
137:                res[0] = advance;
138:                res[1] = angle;
139:
140:                return res;
141:            }
142:
143:            /**
144:             * Returns the next position to the right from the current caret position
145:             * @param hitInfo - current position
146:             * @return next position to the right
147:             */
148:            public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
149:                checkHit(hitInfo);
150:                int visual = getVisualFromHitInfo(hitInfo);
151:
152:                if (visual == breaker.getCharCount()) {
153:                    return null;
154:                }
155:
156:                TextHitInfo newInfo;
157:
158:                while (visual <= breaker.getCharCount()) {
159:                    visual++;
160:                    newInfo = getHitInfoFromVisual(visual);
161:
162:                    if (newInfo.getCharIndex() >= breaker.logical2segment.length) {
163:                        return newInfo;
164:                    }
165:
166:                    if (hitInfo.getCharIndex() >= 0) { // Don't check for leftmost info
167:                        if (breaker.logical2segment[newInfo.getCharIndex()] != breaker.logical2segment[hitInfo
168:                                .getCharIndex()]) {
169:                            return newInfo; // We crossed segment boundary
170:                        }
171:                    }
172:
173:                    TextRunSegment seg = breaker.runSegments
174:                            .get(breaker.logical2segment[newInfo.getCharIndex()]);
175:                    if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
176:                        return newInfo;
177:                    }
178:                }
179:
180:                return null;
181:            }
182:
183:            /**
184:             * Returns the next position to the left from the current caret position
185:             * @param hitInfo - current position
186:             * @return next position to the left
187:             */
188:            public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
189:                checkHit(hitInfo);
190:                int visual = getVisualFromHitInfo(hitInfo);
191:
192:                if (visual == 0) {
193:                    return null;
194:                }
195:
196:                TextHitInfo newInfo;
197:
198:                while (visual >= 0) {
199:                    visual--;
200:                    newInfo = getHitInfoFromVisual(visual);
201:
202:                    if (newInfo.getCharIndex() < 0) {
203:                        return newInfo;
204:                    }
205:
206:                    // Don't check for rightmost info
207:                    if (hitInfo.getCharIndex() < breaker.logical2segment.length) {
208:                        if (breaker.logical2segment[newInfo.getCharIndex()] != breaker.logical2segment[hitInfo
209:                                .getCharIndex()]) {
210:                            return newInfo; // We crossed segment boundary
211:                        }
212:                    }
213:
214:                    TextRunSegment seg = breaker.runSegments
215:                            .get(breaker.logical2segment[newInfo.getCharIndex()]);
216:                    if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
217:                        return newInfo;
218:                    }
219:                }
220:
221:                return null;
222:            }
223:
224:            /**
225:             * For each visual caret position there are two hits. For the simple LTR text one is
226:             * a trailing of the previous char and another is the leading of the next char. This
227:             * method returns the opposite hit for the given hit.
228:             * @param hitInfo - given hit
229:             * @return opposite hit
230:             */
231:            public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
232:                checkHit(hitInfo);
233:
234:                int idx = hitInfo.getCharIndex();
235:
236:                int resIdx;
237:                boolean resIsLeading;
238:
239:                if (idx >= 0 && idx < breaker.getCharCount()) { // Hit info in the middle
240:                    int visual = breaker.getVisualFromLogical(idx);
241:
242:                    // Char is LTR + LEADING info
243:                    if (((breaker.getLevel(idx) & 0x1) == 0x0)
244:                            ^ hitInfo.isLeadingEdge()) {
245:                        visual++;
246:                        if (visual == breaker.getCharCount()) {
247:                            if (breaker.isLTR()) {
248:                                resIdx = breaker.getCharCount();
249:                                resIsLeading = true;
250:                            } else {
251:                                resIdx = -1;
252:                                resIsLeading = false;
253:                            }
254:                        } else {
255:                            resIdx = breaker.getLogicalFromVisual(visual);
256:                            if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
257:                                resIsLeading = true;
258:                            } else {
259:                                resIsLeading = false;
260:                            }
261:                        }
262:                    } else {
263:                        visual--;
264:                        if (visual == -1) {
265:                            if (breaker.isLTR()) {
266:                                resIdx = -1;
267:                                resIsLeading = false;
268:                            } else {
269:                                resIdx = breaker.getCharCount();
270:                                resIsLeading = true;
271:                            }
272:                        } else {
273:                            resIdx = breaker.getLogicalFromVisual(visual);
274:                            if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
275:                                resIsLeading = false;
276:                            } else {
277:                                resIsLeading = true;
278:                            }
279:                        }
280:                    }
281:                } else if (idx < 0) { // before "start"
282:                    if (breaker.isLTR()) {
283:                        resIdx = breaker.getLogicalFromVisual(0);
284:                        resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // LTR char?
285:                    } else {
286:                        resIdx = breaker.getLogicalFromVisual(breaker
287:                                .getCharCount() - 1);
288:                        resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // RTL char?
289:                    }
290:                } else { // idx == breaker.getCharCount()
291:                    if (breaker.isLTR()) {
292:                        resIdx = breaker.getLogicalFromVisual(breaker
293:                                .getCharCount() - 1);
294:                        resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // LTR char?
295:                    } else {
296:                        resIdx = breaker.getLogicalFromVisual(0);
297:                        resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // RTL char?
298:                    }
299:                }
300:
301:                return resIsLeading ? TextHitInfo.leading(resIdx) : TextHitInfo
302:                        .trailing(resIdx);
303:            }
304:
305:            public Line2D getCaretShape(TextHitInfo hitInfo, TextLayout layout) {
306:                return getCaretShape(hitInfo, layout, true, false, null);
307:            }
308:
309:            /**
310:             * Creates a caret shape.
311:             * @param hitInfo - hit where to place a caret
312:             * @param layout - text layout
313:             * @param useItalic - unused for now, was used to create
314:             * slanted carets for italic text
315:             * @param useBounds - true if the cared should fit into the provided bounds
316:             * @param bounds - bounds for the caret
317:             * @return caret shape
318:             */
319:            public Line2D getCaretShape(TextHitInfo hitInfo, TextLayout layout,
320:                    boolean useItalic, boolean useBounds, Rectangle2D bounds) {
321:                checkHit(hitInfo);
322:
323:                float x1, x2, y1, y2;
324:
325:                int charIdx = hitInfo.getCharIndex();
326:
327:                if (charIdx >= 0 && charIdx < breaker.getCharCount()) {
328:                    TextRunSegment segment = breaker.runSegments
329:                            .get(breaker.logical2segment[charIdx]);
330:                    y1 = segment.metrics.descent;
331:                    y2 = -segment.metrics.ascent - segment.metrics.leading;
332:
333:                    x1 = x2 = segment.getCharPosition(charIdx)
334:                            + (hitInfo.isLeadingEdge() ? 0 : segment
335:                                    .getCharAdvance(charIdx));
336:                    // Decided that straight cursor looks better even for italic fonts,
337:                    // especially combined with highlighting
338:                    /*
339:                    // Not graphics, need to check italic angle and baseline
340:                    if (layout.getBaseline() >= 0) {
341:                        if (segment.metrics.italicAngle != 0 && useItalic) {
342:                            x1 -= segment.metrics.italicAngle * segment.metrics.descent;
343:                            x2 += segment.metrics.italicAngle *
344:                                (segment.metrics.ascent + segment.metrics.leading);
345:
346:                            float baselineOffset =
347:                                layout.getBaselineOffsets()[layout.getBaseline()];
348:                            y1 += baselineOffset;
349:                            y2 += baselineOffset;
350:                        }
351:                    }
352:                     */
353:                } else {
354:                    y1 = layout.getDescent();
355:                    y2 = -layout.getAscent() - layout.getLeading();
356:                    x1 = x2 = ((breaker.getBaseLevel() & 0x1) == 0 ^ charIdx < 0) ? layout
357:                            .getAdvance()
358:                            : 0;
359:                }
360:
361:                if (useBounds) {
362:                    y1 = (float) bounds.getMaxY();
363:                    y2 = (float) bounds.getMinY();
364:
365:                    if (x2 > bounds.getMaxX()) {
366:                        x1 = x2 = (float) bounds.getMaxX();
367:                    }
368:                    if (x1 < bounds.getMinX()) {
369:                        x1 = x2 = (float) bounds.getMinX();
370:                    }
371:                }
372:
373:                return new Line2D.Float(x1, y1, x2, y2);
374:            }
375:
376:            /**
377:             * Creates caret shapes for the specified offset. On the boundaries where
378:             * the text is changing its direction this method may return two shapes
379:             * for the strong and the weak carets, in other cases it would return one.
380:             * @param offset - offset in the text.
381:             * @param bounds - bounds to fit the carets into
382:             * @param policy - caret policy
383:             * @param layout - text layout
384:             * @return one or two caret shapes
385:             */
386:            public Shape[] getCaretShapes(int offset, Rectangle2D bounds,
387:                    TextLayout.CaretPolicy policy, TextLayout layout) {
388:                TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
389:                TextHitInfo hit2 = getVisualOtherHit(hit1);
390:
391:                Shape caret1 = getCaretShape(hit1, layout);
392:
393:                if (getVisualFromHitInfo(hit1) == getVisualFromHitInfo(hit2)) {
394:                    return new Shape[] { caret1, null };
395:                }
396:                Shape caret2 = getCaretShape(hit2, layout);
397:
398:                TextHitInfo strongHit = policy.getStrongCaret(hit1, hit2,
399:                        layout);
400:                return strongHit.equals(hit1) ? new Shape[] { caret1, caret2 }
401:                        : new Shape[] { caret2, caret1 };
402:            }
403:
404:            /**
405:             * Connects two carets to produce a highlight shape.
406:             * @param caret1 - 1st caret
407:             * @param caret2 - 2nd caret
408:             * @return highlight shape
409:             */
410:            GeneralPath connectCarets(Line2D caret1, Line2D caret2) {
411:                GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
412:                path.moveTo((float) caret1.getX1(), (float) caret1.getY1());
413:                path.lineTo((float) caret2.getX1(), (float) caret2.getY1());
414:                path.lineTo((float) caret2.getX2(), (float) caret2.getY2());
415:                path.lineTo((float) caret1.getX2(), (float) caret1.getY2());
416:
417:                path.closePath();
418:
419:                return path;
420:            }
421:
422:            /**
423:             * Creates a highlight shape from given two hits. This shape
424:             * will always be visually contiguous
425:             * @param hit1 - 1st hit
426:             * @param hit2 - 2nd hit
427:             * @param bounds - bounds to fit the shape into
428:             * @param layout - text layout
429:             * @return highlight shape
430:             */
431:            public Shape getVisualHighlightShape(TextHitInfo hit1,
432:                    TextHitInfo hit2, Rectangle2D bounds, TextLayout layout) {
433:                checkHit(hit1);
434:                checkHit(hit2);
435:
436:                Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
437:                Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
438:
439:                return connectCarets(caret1, caret2);
440:            }
441:
442:            /**
443:             * Suppose that the user visually selected a block of text which has
444:             * several different levels (mixed RTL and LTR), so, in the logical
445:             * representation of the text this selection may be not contigous.
446:             * This methods returns a set of logical ranges for the arbitrary
447:             * visual selection represented by two hits.
448:             * @param hit1 - 1st hit
449:             * @param hit2 - 2nd hit
450:             * @return logical ranges for the selection
451:             */
452:            public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1,
453:                    TextHitInfo hit2) {
454:                checkHit(hit1);
455:                checkHit(hit2);
456:
457:                int visual1 = getVisualFromHitInfo(hit1);
458:                int visual2 = getVisualFromHitInfo(hit2);
459:
460:                if (visual1 > visual2) {
461:                    int tmp = visual2;
462:                    visual2 = visual1;
463:                    visual1 = tmp;
464:                }
465:
466:                // Max level is 255, so we don't need more than 512 entries
467:                int results[] = new int[512];
468:
469:                int prevLogical, logical, runStart, numRuns = 0;
470:
471:                logical = runStart = prevLogical = breaker
472:                        .getLogicalFromVisual(visual1);
473:
474:                // Get all the runs. We use the fact that direction is constant in all runs.
475:                for (int i = visual1 + 1; i <= visual2; i++) {
476:                    logical = breaker.getLogicalFromVisual(i);
477:                    int diff = logical - prevLogical;
478:
479:                    // Start of the next run encountered
480:                    if (diff > 1 || diff < -1) {
481:                        results[(numRuns) * 2] = Math
482:                                .min(runStart, prevLogical);
483:                        results[(numRuns) * 2 + 1] = Math.max(runStart,
484:                                prevLogical);
485:                        numRuns++;
486:                        runStart = logical;
487:                    }
488:
489:                    prevLogical = logical;
490:                }
491:
492:                // The last unsaved run
493:                results[(numRuns) * 2] = Math.min(runStart, logical);
494:                results[(numRuns) * 2 + 1] = Math.max(runStart, logical);
495:                numRuns++;
496:
497:                int retval[] = new int[numRuns * 2];
498:                System.arraycopy(results, 0, retval, 0, numRuns * 2);
499:                return retval;
500:            }
501:
502:            /**
503:             * Creates a highlight shape from given two endpoints in the logical
504:             * representation. This shape is not always visually contiguous
505:             * @param firstEndpoint - 1st logical endpoint
506:             * @param secondEndpoint - 2nd logical endpoint
507:             * @param bounds - bounds to fit the shape into
508:             * @param layout - text layout
509:             * @return highlight shape
510:             */
511:            public Shape getLogicalHighlightShape(int firstEndpoint,
512:                    int secondEndpoint, Rectangle2D bounds, TextLayout layout) {
513:                GeneralPath res = new GeneralPath();
514:
515:                for (int i = firstEndpoint; i <= secondEndpoint; i++) {
516:                    int endRun = breaker.getLevelRunLimit(i, secondEndpoint);
517:                    TextHitInfo hit1 = TextHitInfo.leading(i);
518:                    TextHitInfo hit2 = TextHitInfo.trailing(endRun - 1);
519:
520:                    Line2D caret1 = getCaretShape(hit1, layout, false, true,
521:                            bounds);
522:                    Line2D caret2 = getCaretShape(hit2, layout, false, true,
523:                            bounds);
524:
525:                    res.append(connectCarets(caret1, caret2), false);
526:
527:                    i = endRun;
528:                }
529:
530:                return res;
531:            }
532:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.