Source Code Cross Referenced for StyledTextBidi.java in  » IDE-Eclipse » swt » org » eclipse » swt » custom » 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 » IDE Eclipse » swt » org.eclipse.swt.custom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2003 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.swt.custom;
0011:
0012:        import java.util.*;
0013:        import org.eclipse.swt.*;
0014:        import org.eclipse.swt.graphics.*;
0015:        import org.eclipse.swt.internal.*;
0016:        import org.eclipse.swt.widgets.*;
0017:
0018:        /**
0019:         * This class provides API for StyledText to implement bidirectional text
0020:         * functions.
0021:         * Objects of this class are created for a single line of text.
0022:         */
0023:        class StyledTextBidi {
0024:            private GC gc;
0025:            private int[] bidiSegments; // bidi text segments, each segment will be rendered separately
0026:            private int[] renderPositions; // x position at which characters of the line are rendered, in visual order
0027:            private int[] order; // reordering indices in logical order, iV=order[iL] (iV=visual index, iL=logical index),
0028:            // if no character in a line needs reordering all iV and iL are the same.
0029:            private int[] dx; // distance between character cells. in visual order. renderPositions[iV + 1] = renderPositions[iV] + dx[iV]
0030:            private byte[] classBuffer; // the character types in logical order, see BidiUtil for the possible types
0031:            private char[] glyphBuffer; // the glyphs in visual order as they will be rendered on screen.
0032:            private boolean isRightOriented;// writing orientation
0033:
0034:            /** 
0035:             * This class describes a text segment of a single direction, either 
0036:             * left-to-right (L2R) or right-to-left (R2L). 
0037:             * Objects of this class are used by StyledTextBidi rendering methods 
0038:             * to render logically contiguous text segments that may be visually 
0039:             * discontiguous if they consist of different directions.
0040:             */
0041:            class DirectionRun {
0042:                int logicalStart;
0043:                int logicalEnd;
0044:
0045:                DirectionRun(int logicalStart, int logicalEnd) {
0046:                    this .logicalStart = logicalStart;
0047:                    this .logicalEnd = logicalEnd;
0048:                }
0049:
0050:                int getVisualStart() {
0051:                    int visualStart = order[logicalStart];
0052:                    int visualEnd = order[logicalEnd];
0053:                    // the visualStart of a R2L direction run is actually
0054:                    // at the run's logicalEnd, answered as such since rendering 
0055:                    // always occurs from L2R regardless of the text run's
0056:                    // direction
0057:                    if (visualEnd < visualStart) {
0058:                        visualStart = visualEnd;
0059:                    }
0060:                    return visualStart;
0061:                }
0062:
0063:                int getVisualEnd() {
0064:                    int visualStart = order[logicalStart];
0065:                    int visualEnd = order[logicalEnd];
0066:                    // the visualEnd of a R2L direction run is actually
0067:                    // at the run's logicalStart, answered as such since rendering 
0068:                    // always occurs from L2R regardless of the text run's
0069:                    // direction
0070:                    if (visualEnd < visualStart) {
0071:                        visualEnd = visualStart;
0072:                    }
0073:                    return visualEnd;
0074:                }
0075:
0076:                int getRenderStartX() {
0077:                    return renderPositions[getVisualStart()];
0078:                }
0079:
0080:                int getRenderStopX() {
0081:                    int visualEnd = getVisualEnd();
0082:
0083:                    return renderPositions[visualEnd] + dx[visualEnd];
0084:                }
0085:
0086:                public String toString() {
0087:                    StringBuffer buf = new StringBuffer();
0088:                    buf.append("vStart,Stop:" + getVisualStart() + ","
0089:                            + getVisualEnd() + " lStart,Stop:" + logicalStart
0090:                            + "," + logicalEnd + " renderStart,Stop: "
0091:                            + getRenderStartX() + "," + getRenderStopX());
0092:                    return buf.toString();
0093:                }
0094:            }
0095:
0096:            /**
0097:             * Constructs an instance of this class for a line of text. The text 
0098:             * is reordered to reflect how it will be displayed.
0099:             * <p>
0100:             * 
0101:             * @param gc the GC to use for rendering and measuring of this line.
0102:             * @param tabWidth tab width in number of spaces, used to calculate 
0103:             * 	tab stops
0104:             * @param text line that bidi data should be calculated for
0105:             * @param boldRanges bold text segments in the line, specified as 
0106:             * 	i=bold start,i+1=bold length
0107:             * @param boldFont font that bold text will be rendered in, needed for 
0108:             * 	proper measuring of bold text segments.
0109:             * @param offset text segments that should be measured and reordered 
0110:             * 	separately, may be needed to preserve the order of separate R2L 
0111:             * 	segments to each other. Must have at least two elements, 0 and the text
0112:             * 	length.
0113:             */
0114:            public StyledTextBidi(GC gc, int tabWidth, String text,
0115:                    StyleRange[] ranges, Font boldFont, int[] offsets) {
0116:                int length = text.length();
0117:                isRightOriented = (gc.getStyle() & SWT.MIRRORED) != 0;
0118:
0119:                this .gc = gc;
0120:                bidiSegments = offsets;
0121:                renderPositions = new int[length];
0122:                order = new int[length];
0123:                dx = new int[length];
0124:                classBuffer = new byte[length];
0125:                if (length == 0) {
0126:                    glyphBuffer = new char[0];
0127:                } else {
0128:                    glyphBuffer = BidiUtil.getRenderInfo(gc, text, order,
0129:                            classBuffer, dx, 0, offsets);
0130:                    if (ranges != null) {
0131:                        // If the font supports characters shaping, break up the font style ranges based on 
0132:                        // the specified bidi segments.  Each bidi segment will be treated separately 
0133:                        // for font style purposes.
0134:                        StyleRange[] segmentedRanges;
0135:                        if (isCharacterShaped(gc))
0136:                            segmentedRanges = getSegmentedRangesFor(ranges);
0137:                        else
0138:                            segmentedRanges = ranges;
0139:                        Font normalFont = gc.getFont();
0140:                        gc.setFont(boldFont);
0141:                        for (int i = 0; i < segmentedRanges.length; i++) {
0142:                            StyleRange segmentedRange = segmentedRanges[i];
0143:                            int rangeStart = segmentedRange.start;
0144:                            int rangeLength = segmentedRange.length;
0145:                            // Font styled text needs to be processed so that the dx array reflects the styled
0146:                            // font.
0147:                            prepareFontStyledText(text, rangeStart, rangeLength);
0148:                        }
0149:                        gc.setFont(normalFont);
0150:                    }
0151:                    calculateTabStops(text, tabWidth);
0152:                    calculateRenderPositions();
0153:                }
0154:            }
0155:
0156:            /**
0157:             * Constructs an instance of this class for a line of text. This constructor
0158:             * should be used when only ordering (not rendering) information is needed.  
0159:             * Only the class and order arrays will be filled during this call.
0160:             * <p>
0161:             * 
0162:             * @param gc the GC to use for rendering and measuring of this line.
0163:             * @param text line that bidi data should be calculated for
0164:             * @param offset text segments that should be measured and reordered 
0165:             * 	separately, may be needed to preserve the order of separate R2L 
0166:             * 	segments to each other
0167:             */
0168:            public StyledTextBidi(GC gc, String text, int[] offsets) {
0169:                int length = text.length();
0170:                isRightOriented = (gc.getStyle() & SWT.MIRRORED) != 0;
0171:                this .gc = gc;
0172:                bidiSegments = offsets;
0173:                order = new int[length];
0174:                classBuffer = new byte[length];
0175:                BidiUtil.getOrderInfo(gc, text, order, classBuffer, 0, offsets);
0176:                // initialize the unused arrays
0177:                dx = new int[0];
0178:                renderPositions = new int[0];
0179:                glyphBuffer = new char[0];
0180:
0181:            }
0182:
0183:            /**
0184:             * Adds a listener that should be called when the user changes the 
0185:             * keyboard layout for the specified window.
0186:             * <p>
0187:             * 
0188:             * @param control Control to add the keyboard language listener for.
0189:             * 	Each window has its own keyboard language setting.
0190:             * @param runnable the listener that should be called when the user 
0191:             * 	changes the keyboard layout.
0192:             */
0193:            static void addLanguageListener(Control control, Runnable runnable) {
0194:                BidiUtil.addLanguageListener(control.handle, runnable);
0195:            }
0196:
0197:            /**
0198:             * Answers the direction of the active keyboard language - either 
0199:             * L2R or R2L.  The active keyboard language determines the direction 
0200:             * of the caret and can be changed by the user (e.g., via Alt-Shift on
0201:             * Win32 platforms).
0202:             * <p>
0203:             * 
0204:             * @return the direction of the active keyboard language. SWT.LEFT (for L2R
0205:             *  language) or SWT.RIGHT (for R2L language) or SWT.DEFAULT if no R2L languages
0206:             * are installed.
0207:             */
0208:            static int getKeyboardLanguageDirection() {
0209:                int language = BidiUtil.getKeyboardLanguage();
0210:                if (language == BidiUtil.KEYBOARD_BIDI) {
0211:                    return SWT.RIGHT;
0212:                }
0213:                if (BidiUtil.isKeyboardBidi()) {
0214:                    return SWT.LEFT;
0215:                }
0216:                return SWT.DEFAULT;
0217:            }
0218:
0219:            /**
0220:             * Returns whether the current platform supports a bidi language.
0221:             * <p>
0222:             * 
0223:             * @return true=bidi is supported, false otherwise. 
0224:             */
0225:            static boolean isBidiPlatform() {
0226:                return BidiUtil.isBidiPlatform();
0227:            }
0228:
0229:            /**
0230:             * Returns whether the font set in the specified gc supports 
0231:             * character shaping.
0232:             * <p>
0233:             * 
0234:             * @param gc the GC that should be tested for character shaping.
0235:             * @return 
0236:             * 	true=the font set in the specified gc supports character shaped glyphs
0237:             * 	false=the font set in the specified gc doesn't support character shaped glyphs 
0238:             */
0239:            static boolean isCharacterShaped(GC gc) {
0240:                return (BidiUtil.getFontBidiAttributes(gc) & BidiUtil.GLYPHSHAPE) != 0;
0241:            }
0242:
0243:            /**
0244:             * Returns whether the font set in the specified gc contains 
0245:             * ligatured glyphs.
0246:             * <p>
0247:             * 
0248:             * @param gc the GC that should be tested for ligatures.
0249:             * @return 
0250:             * 	true=the font set in the specified gc contains ligatured glyphs. 
0251:             * 	false=the font set in the specified gc doesn't contain ligatured 
0252:             * 	glyphs. 
0253:             */
0254:            static boolean isLigated(GC gc) {
0255:                return (BidiUtil.getFontBidiAttributes(gc) & BidiUtil.LIGATE) != 0;
0256:            }
0257:
0258:            /**
0259:             * Removes the keyboard language listener for the specified window.
0260:             * <p>
0261:             * 
0262:             * @param control window to remove the keyboard language listener from.
0263:             */
0264:            static void removeLanguageListener(Control control) {
0265:                BidiUtil.removeLanguageListener(control.handle);
0266:            }
0267:
0268:            /**
0269:             * Calculates render positions using the glyph distance values in the dx array.
0270:             */
0271:            private void calculateRenderPositions() {
0272:                renderPositions = new int[dx.length];
0273:                renderPositions[0] = StyledText.XINSET;
0274:                for (int i = 0; i < dx.length - 1; i++) {
0275:                    renderPositions[i + 1] = renderPositions[i] + dx[i];
0276:                }
0277:            }
0278:
0279:            /**
0280:             * Calculate the line's tab stops and adjust the dx array to 
0281:             * reflect the width of tab characters.
0282:             * <p>
0283:             * 
0284:             * @param text the original line text (not reordered) containing 
0285:             * 	tab characters.
0286:             * @param tabWidth number of pixels that one tab character represents
0287:             */
0288:            private void calculateTabStops(String text, int tabWidth) {
0289:                int tabIndex = text.indexOf('\t', 0);
0290:                int logicalIndex = 0;
0291:                int x = 0;
0292:                int spaceWidth = gc.stringExtent(" ").x;
0293:
0294:                while (tabIndex != -1) {
0295:                    for (; logicalIndex < tabIndex; logicalIndex++) {
0296:                        x += dx[order[logicalIndex]];
0297:                    }
0298:                    int tabStop = x + tabWidth;
0299:                    // make sure tab stop is at least one space width apart 
0300:                    // from the last character. fixes 4844.
0301:                    if (tabWidth - tabStop % tabWidth < spaceWidth) {
0302:                        tabStop += tabWidth;
0303:                    }
0304:                    tabStop -= tabStop % tabWidth;
0305:                    dx[order[tabIndex]] = tabStop - x;
0306:                    tabIndex = text.indexOf('\t', tabIndex + 1);
0307:                }
0308:            }
0309:
0310:            /** 
0311:             * Renders the specified text segment.  All text is rendered L2R
0312:             * regardless of the direction of the text.  The rendered text may 
0313:             * be visually discontiguous if the text segment is bidirectional.
0314:             * <p>
0315:             * 
0316:             * @param logicalStart start offset in the logical text
0317:             * @param length number of logical characters to render
0318:             * @param xOffset x location of the line start
0319:             * @param yOffset y location of the line start 
0320:             */
0321:            void drawBidiText(String text, int logicalStart, int length,
0322:                    int xOffset, int yOffset) {
0323:                Enumeration directionRuns;
0324:                int endOffset = logicalStart + length;
0325:
0326:                if (logicalStart < 0 || endOffset > getTextLength()) {
0327:                    return;
0328:                }
0329:                directionRuns = getDirectionRuns(logicalStart, length)
0330:                        .elements();
0331:                while (directionRuns.hasMoreElements()) {
0332:                    DirectionRun run = (DirectionRun) directionRuns
0333:                            .nextElement();
0334:                    int x = xOffset + run.getRenderStartX();
0335:                    if (glyphBuffer != null) {
0336:                        int visualStart = run.getVisualStart();
0337:                        int visualEnd = run.getVisualEnd();
0338:                        drawGlyphs(visualStart, visualEnd - visualStart + 1, x,
0339:                                yOffset);
0340:                    } else {
0341:                        drawChars(text, run.logicalStart, run.logicalEnd, x,
0342:                                yOffset, classBuffer[run.logicalStart]);
0343:                    }
0344:                }
0345:            }
0346:
0347:            /**
0348:             * Renders a segment of glyphs. Glyphs are visual objects so the
0349:             * start and length are visual as well.  Glyphs are always rendered L2R.
0350:             * <p>
0351:             * 
0352:             * @param visualStart start offset of the glyphs to render relative to the 
0353:             * 	line start.
0354:             * @param length number of glyphs to render
0355:             * @param x x location to render at
0356:             * @param y y location to render at
0357:             */
0358:            private void drawGlyphs(int visualStart, int length, int x, int y) {
0359:                char[] renderBuffer = new char[length];
0360:                int[] renderDx = new int[length];
0361:                if (length == 0) {
0362:                    return;
0363:                }
0364:                System.arraycopy(glyphBuffer, visualStart, renderBuffer, 0,
0365:                        length);
0366:                // copy the distance values for the desired rendering range
0367:                System.arraycopy(dx, visualStart, renderDx, 0, length);
0368:                BidiUtil.drawGlyphs(gc, renderBuffer, renderDx, x, y);
0369:            }
0370:
0371:            private void drawChars(String text, int startOffset, int endOffset,
0372:                    int x, int y, byte bidiClass) {
0373:                BidiUtil.drawChars(gc, text, startOffset, endOffset, x, y,
0374:                        bidiClass, order, renderPositions, dx);
0375:            }
0376:
0377:            /** 
0378:             * Fills a rectangle spanning the given logical range.
0379:             * The rectangle may be visually discontiguous if the text segment 
0380:             * is bidirectional.
0381:             * <p>
0382:             * 
0383:             * @param logicalStart logcial start offset of the rectangle
0384:             * @param length number of logical characters the rectangle should span
0385:             * @param xOffset x location of the line start
0386:             * @param yOffset y location of the line start
0387:             * @param height height of the rectangle
0388:             */
0389:            void fillBackground(int logicalStart, int length, int xOffset,
0390:                    int yOffset, int height) {
0391:                Enumeration directionRuns = getDirectionRuns(logicalStart,
0392:                        length).elements();
0393:
0394:                if (logicalStart < 0 || logicalStart + length > getTextLength()) {
0395:                    return;
0396:                }
0397:                while (directionRuns.hasMoreElements()) {
0398:                    DirectionRun run = (DirectionRun) directionRuns
0399:                            .nextElement();
0400:                    int startX = run.getRenderStartX();
0401:                    gc.fillRectangle(xOffset + startX, yOffset, run
0402:                            .getRenderStopX()
0403:                            - startX, height);
0404:                }
0405:            }
0406:
0407:            /**
0408:             * Returns the offset and direction that will be used to position the caret for 
0409:             * the given x location.  The caret will be placed in front of or behind the
0410:             * character at location x depending on what type of character (i.e., R2L or L2R)
0411:             * is at location x.  This method is used for positioning the caret when a mouse
0412:             * click occurs within the widget.
0413:             * <p>
0414:             * 
0415:             * @param x the x location of the character in the line.
0416:             * @return array containing the caret offset and direction for the x location.
0417:             * 	index 0: offset relative to the start of the line
0418:             * 	index 1: direction, either ST.COLUMN_NEXT or ST.COLUMN_PREVIOUS.
0419:             *	The direction is used to control the caret position at direction 
0420:             * 	boundaries. The semantics follow the behavior for keyboard cursor 
0421:             * 	navigation. 
0422:             * 	Example: RRRLLL
0423:             * 	Pressing cursor left (COLUMN_PREVIOUS) in the L2R segment places the cursor 
0424:             * 	in front of the first character of the L2R segment. Pressing cursor right 
0425:             * 	(COLUMN_NEXT) in a R2L segment places the cursor behind the last character 
0426:             * 	of the R2L segment. However, both are the same logical offset.
0427:             */
0428:            int[] getCaretOffsetAndDirectionAtX(int x) {
0429:                int lineLength = getTextLength();
0430:
0431:                if (lineLength == 0) {
0432:                    return new int[] { 0, 0 };
0433:                }
0434:                int eol = renderPositions[renderPositions.length - 1]
0435:                        + dx[dx.length - 1];
0436:                if (x >= eol) {
0437:                    return new int[] { lineLength, ST.COLUMN_NEXT };
0438:                }
0439:                // get the visual offset of the clicked character
0440:                int visualOffset = getVisualOffsetAtX(x);
0441:                // figure out if the character was clicked on the right or left
0442:                int halfway = renderPositions[visualOffset] + dx[visualOffset]
0443:                        / 2;
0444:                boolean visualLeft;
0445:                int offset = getLogicalOffset(visualOffset);
0446:                int direction;
0447:
0448:                if (isRightOriented) {
0449:                    visualLeft = (x > halfway);
0450:                } else {
0451:                    visualLeft = (x <= halfway);
0452:                }
0453:                if (isRightToLeft(offset)) {
0454:                    if (visualLeft) {
0455:                        if (isLigated(gc)) {
0456:                            // the caret should be positioned after the last
0457:                            // character of the ligature
0458:                            offset = getLigatureEndOffset(offset);
0459:                        }
0460:                        offset++;
0461:                        // position the caret as if the caret is to the right
0462:                        // of the character at location x and the NEXT key is
0463:                        // pressed
0464:                        direction = ST.COLUMN_NEXT;
0465:                    } else {
0466:                        // position the caret as if the caret is to the left
0467:                        // of the character at location x and the PREVIOUS 
0468:                        // key is pressed				
0469:                        direction = ST.COLUMN_PREVIOUS;
0470:                    }
0471:                } else {
0472:                    if (visualLeft) {
0473:                        // position the caret as if the caret is to the left
0474:                        // of the character at location x and the PREVIOUS 
0475:                        // key is pressed				
0476:                        direction = ST.COLUMN_PREVIOUS;
0477:                    } else {
0478:                        offset++;
0479:                        // position the caret as if the caret is to the right
0480:                        // of the character at location x and the NEXT key is
0481:                        // pressed
0482:                        direction = ST.COLUMN_NEXT;
0483:                    }
0484:                }
0485:                return new int[] { offset, direction };
0486:            }
0487:
0488:            /**
0489:             * Returns the direction segments that are in the specified text
0490:             * range. The text range may be visually discontiguous if the 
0491:             * text is bidirectional. Each returned direction run has a single 
0492:             * direction and the runs all go from left to right, regardless of
0493:             * the direction of the text in the segment.  User specified segments 
0494:             * (via BidiSegmentListener) are taken into account and result in 
0495:             * separate direction runs.
0496:             * <p>
0497:             * 
0498:             * @param logicalStart offset of the logcial start of the first 
0499:             * 	direction segment
0500:             * @param length length of the text included in the direction 
0501:             * 	segments
0502:             * @return the direction segments that are in the specified 
0503:             *  text range, each segment has a single direction.
0504:             */
0505:            private Vector getDirectionRuns(int logicalStart, int length) {
0506:                Vector directionRuns = new Vector();
0507:                int logicalEnd = logicalStart + length - 1;
0508:                int segmentLogicalStart = logicalStart;
0509:                int segmentLogicalEnd = segmentLogicalStart;
0510:                int checkSide = isRightOriented ? -1 : 1;
0511:
0512:                if (logicalEnd < getTextLength()) {
0513:                    int bidiSegmentIndex = 0;
0514:                    int bidiSegmentEnd = bidiSegments[bidiSegmentIndex + 1];
0515:
0516:                    // Find the bidi segment that the direction runs start in.
0517:                    // There will always be at least on bidi segment (for the entire line).
0518:                    while (bidiSegmentIndex < bidiSegments.length - 2
0519:                            && bidiSegmentEnd <= logicalStart) {
0520:                        bidiSegmentIndex++;
0521:                        bidiSegmentEnd = bidiSegments[bidiSegmentIndex + 1];
0522:                    }
0523:                    while (segmentLogicalEnd <= logicalEnd) {
0524:                        boolean isRightToLeftSegment = isRightToLeft(segmentLogicalStart);
0525:                        // Search for the end of the direction segment. Each segment needs to 
0526:                        // be rendered separately. 
0527:                        // E.g., 11211 (1=R2L, 2=L2R), rendering from logical index 0 to 5 
0528:                        // would be visual 1 to 4 and would thus miss visual 0. Rendering the 
0529:                        // segments separately would render from visual 1 to 0, then 2, then 
0530:                        // 4 to 3.
0531:                        while (segmentLogicalEnd < logicalEnd
0532:                                &&
0533:                                // If our segment type is RtoL, the order index for the next character should be one less, if there
0534:                                // is no direction change.
0535:                                // If our segment type is LtoR, the order index for the next character will be one more if there is
0536:                                // no direction change.
0537:                                (order[segmentLogicalEnd + 1] == order[segmentLogicalEnd]
0538:                                        || // treat ligatures as part of the direction segment
0539:                                        (isRightToLeftSegment && (order[segmentLogicalEnd + 1]
0540:                                                + checkSide == order[segmentLogicalEnd])) || (isRightToLeftSegment == false && (order[segmentLogicalEnd + 1]
0541:                                        - checkSide == order[segmentLogicalEnd])))
0542:                                &&
0543:                                // For correct numeric shaping, don't mix segments with different bidi classes.
0544:                                // E.g., logical ABC3 (capitalized=R2L, 3=local number) would be visually completely reversed - 3CBA, however,
0545:                                // it's not homogeneous and consists of 2 different directional runs.
0546:                                // Compare: logical ABC34 (4=another local number) look in visual form as 34CBA, i.e. not completely reversed.
0547:                                classBuffer[segmentLogicalEnd + 1] == classBuffer[segmentLogicalEnd]
0548:                                && segmentLogicalEnd + 1 < bidiSegmentEnd) {
0549:                            segmentLogicalEnd++;
0550:                        }
0551:                        directionRuns.addElement(new DirectionRun(
0552:                                segmentLogicalStart, segmentLogicalEnd));
0553:                        segmentLogicalStart = ++segmentLogicalEnd;
0554:                        // The current direction run ends at a bidi segment end. Get the next bidi segment.
0555:                        if (segmentLogicalEnd == bidiSegmentEnd
0556:                                && bidiSegmentIndex < bidiSegments.length - 2) {
0557:                            bidiSegmentIndex++;
0558:                            bidiSegmentEnd = bidiSegments[bidiSegmentIndex + 1];
0559:                        }
0560:                    }
0561:                }
0562:                return directionRuns;
0563:            }
0564:
0565:            /**
0566:             * Returns the offset of the last character comprising a ligature.
0567:             * <p>
0568:             * 
0569:             * @param offset the logical offset of a character that may be a 
0570:             * 	ligature.
0571:             * @return the offset of the last character comprising a ligature.
0572:             */
0573:            int getLigatureEndOffset(int offset) {
0574:                int newOffset = offset;
0575:                int i = offset + 1;
0576:
0577:                // assume only bidi languages support ligatures
0578:                if (offset < 0 || offset >= order.length
0579:                        || isRightToLeft(offset) == false) {
0580:                    return offset;
0581:                }
0582:                // a ligature is a visual character that is comprised of 
0583:                // multiple logical characters, thus each logical part of
0584:                // a ligature will have the same order value
0585:                while (i < order.length && (order[i] == order[offset])) {
0586:                    newOffset = i;
0587:                    i++;
0588:                }
0589:                return newOffset;
0590:            }
0591:
0592:            /**
0593:             * Returns the offset of the first character comprising a ligature.
0594:             * <p>
0595:             * 
0596:             * @param offset the logical offset of a character that may be a 
0597:             * 	ligature.
0598:             * @return the offset of the first character comprising a ligature.
0599:             */
0600:            int getLigatureStartOffset(int offset) {
0601:                int newOffset = offset;
0602:                int i = offset - 1;
0603:
0604:                // assume only bidi languages support ligatures
0605:                if (offset < 0 || offset >= order.length
0606:                        || isRightToLeft(offset) == false) {
0607:                    return offset;
0608:                }
0609:                // a ligature is a visual character that is comprised of 
0610:                // multiple logical characters, thus each logical part of
0611:                // a ligature will have the same order value
0612:                while (i >= 0 && (order[i] == order[offset])) {
0613:                    newOffset = i;
0614:                    i--;
0615:                }
0616:                return newOffset;
0617:            }
0618:
0619:            /**
0620:             * Returns the logical offset of the character at the specified 
0621:             * visual offset.
0622:             * <p>
0623:             * 
0624:             * @param visualOffset the visual offset
0625:             * @return the logical offset of the character at <code>visualOffset</code>.
0626:             */
0627:            int getLogicalOffset(int visualOffset) {
0628:                int logicalOffset = 0;
0629:
0630:                while (logicalOffset < order.length
0631:                        && order[logicalOffset] != visualOffset) {
0632:                    logicalOffset++;
0633:                }
0634:                return logicalOffset;
0635:            }
0636:
0637:            /**
0638:             * Returns the offset of the character at the specified x location.
0639:             * <p>
0640:             * 
0641:             * @param x the location of the character
0642:             * @return the logical offset of the character at the specified x 
0643:             * 	location.
0644:             */
0645:            int getOffsetAtX(int x) {
0646:                int visualOffset;
0647:
0648:                if (getTextLength() == 0) {
0649:                    return 0;
0650:                }
0651:                if (x >= renderPositions[renderPositions.length - 1]
0652:                        + dx[dx.length - 1]) {
0653:                    // Return when x is past the end of the line. Fixes 1GLADBK.
0654:                    return -1;
0655:                }
0656:                visualOffset = getVisualOffsetAtX(x);
0657:                return getLogicalOffset(visualOffset);
0658:            }
0659:
0660:            /**
0661:             * Returns the reordering indices that map between logical and 
0662:             * visual index of characters in the specified range.
0663:             * <p>
0664:             * 
0665:             * @param start start offset of the reordering indices
0666:             * @param length number of reordering indices to return
0667:             * @return the reordering indices that map between logical and 
0668:             * 	visual index of characters in the specified range. Relative 
0669:             * 	to the start of the range.
0670:             */
0671:            private int[] getRenderIndexesFor(int start, int length) {
0672:                int[] positions = new int[length];
0673:                int end = start + length;
0674:
0675:                for (int i = start; i < end; i++) {
0676:                    positions[i - start] = order[i];
0677:                }
0678:                return positions;
0679:            }
0680:
0681:            /**
0682:             * Break up the given ranges such that each range is fully contained within a bidi
0683:             * segment.
0684:             */
0685:            private StyleRange[] getSegmentedRangesFor(StyleRange[] ranges) {
0686:                if ((bidiSegments == null) || (bidiSegments.length == 0))
0687:                    return ranges;
0688:                Vector newRanges = new Vector();
0689:                int j = 0;
0690:                int startSegment;
0691:                int endSegment;
0692:                for (int i = 0; i < ranges.length; i++) {
0693:                    int start = ranges[i].start;
0694:                    int end = start + ranges[i].length;
0695:                    startSegment = -1;
0696:                    endSegment = -1;
0697:                    boolean done = false;
0698:                    while (j < bidiSegments.length && !done) {
0699:                        if (bidiSegments[j] <= start) {
0700:                            startSegment = j;
0701:                        }
0702:                        if (bidiSegments[j] >= end) {
0703:                            endSegment = j - 1;
0704:                            j--;
0705:                        }
0706:                        done = (startSegment != -1) && (endSegment != -1);
0707:                        if (!done)
0708:                            j++;
0709:                    }
0710:                    if (startSegment == endSegment) {
0711:                        // range is within one segment
0712:                        StyleRange newStyle = new StyleRange(start,
0713:                                end - start, null, null);
0714:                        newRanges.addElement(newStyle);
0715:                    } else if (startSegment > endSegment) {
0716:                        // range is within no segment (i.e., it's empty)
0717:                    } else {
0718:                        // range spans multiple segments
0719:                        StyleRange newStyle = new StyleRange(start,
0720:                                bidiSegments[startSegment + 1] - start, null,
0721:                                null);
0722:                        newRanges.addElement(newStyle);
0723:                        startSegment++;
0724:                        for (int k = startSegment; k < endSegment; k++) {
0725:                            newStyle = new StyleRange(bidiSegments[k],
0726:                                    bidiSegments[k + 1] - bidiSegments[k],
0727:                                    null, null);
0728:                            newRanges.addElement(newStyle);
0729:                        }
0730:                        newStyle = new StyleRange(bidiSegments[endSegment], end
0731:                                - bidiSegments[endSegment], null, null);
0732:                        newRanges.addElement(newStyle);
0733:                    }
0734:                }
0735:                StyleRange[] rangeArray = new StyleRange[newRanges.size()];
0736:                for (int i = 0; i < newRanges.size(); i++) {
0737:                    rangeArray[i] = (StyleRange) newRanges.elementAt(i);
0738:                }
0739:                return rangeArray;
0740:            }
0741:
0742:            /**
0743:             * Returns the number of characters in the line.
0744:             * <p>
0745:             * 
0746:             * @return the number of characters in the line.
0747:             */
0748:            private int getTextLength() {
0749:                return dx.length;
0750:            }
0751:
0752:            /**
0753:             * Returns the x position at the specified offset in the line.
0754:             * <p>
0755:             * @param logicalOffset offset of the character in the line.
0756:             * @return the x position at the specified offset in the line.
0757:             */
0758:            int getTextPosition(int logicalOffset) {
0759:                return getTextPosition(logicalOffset, ST.COLUMN_NEXT);
0760:            }
0761:
0762:            /**
0763:             * Returns the x position at the specified offset in the line.
0764:             * The direction parameter is used to determine the position 
0765:             * at direction boundaries.  If the logical offset is between a R2L 
0766:             * and a L2R segment, pressing cursor left in the L2R segment places
0767:             * the position in front of the first character of the L2R segment; whereas
0768:             * pressing cursor right in the R2L segment places the position behind 
0769:             * the last character of the R2L segment. However, both x positions
0770:             * are at the same logical offset.
0771:             * <p>
0772:             * 
0773:             * @param logicalOffset offset of the character in the line
0774:             * @param direction direction the caret moved to the specified location.
0775:             * 	 either ST.COLUMN_NEXT (right cursor key) or ST.COLUMN_PREVIOUS (left cursor key) .
0776:             * @return the x position at the specified offset in the line, 
0777:             * 	taking the direction into account as described above.
0778:             */
0779:            int getTextPosition(int logicalOffset, int direction) {
0780:                int caretX;
0781:
0782:                if (getTextLength() == 0 || logicalOffset < 0) {
0783:                    return StyledText.XINSET;
0784:                }
0785:
0786:                boolean isRightToLeft = isRightToLeft(logicalOffset);
0787:                // at or past end of line?
0788:                if (logicalOffset >= order.length) {
0789:                    logicalOffset = Math.min(logicalOffset, order.length - 1);
0790:                    isRightToLeft = isRightToLeft(logicalOffset);
0791:                    int visualOffset = order[logicalOffset];
0792:                    if ((!isRightOriented && !isRightToLeft)
0793:                            || (isRightOriented && isRightToLeft)) {
0794:                        caretX = renderPositions[visualOffset]
0795:                                + dx[visualOffset];
0796:                    } else {
0797:                        caretX = renderPositions[visualOffset];
0798:                    }
0799:                } else
0800:                // at beginning of line?
0801:                if (logicalOffset == 0) {
0802:                    int visualOffset = order[logicalOffset];
0803:                    if ((!isRightOriented && !isRightToLeft)
0804:                            || (isRightOriented && isRightToLeft)) {
0805:                        caretX = renderPositions[visualOffset];
0806:                    } else {
0807:                        caretX = renderPositions[visualOffset]
0808:                                + dx[visualOffset];
0809:                    }
0810:                } else
0811:                // always consider local numbers as a direction boundary 
0812:                // because they represent a discontiguous text segment coming from 
0813:                // a R2L segment.
0814:                // treat user specified direction segments like real direction changes.
0815:                if (direction == ST.COLUMN_NEXT
0816:                        && (isRightToLeft(logicalOffset) != isRightToLeft(logicalOffset - 1)
0817:                                || isLocalNumber(logicalOffset) != isLocalNumber(logicalOffset - 1) || isStartOfBidiSegment(logicalOffset))) {
0818:                    int visualOffset = order[logicalOffset - 1];
0819:                    // moving between segments.
0820:                    // do not consider local numbers as R2L here, to determine position,
0821:                    // because local numbers are navigated L2R and we want the caret to 
0822:                    // be to the right of the number. see 1GK9API
0823:                    isRightToLeft = isRightToLeft(logicalOffset - 1);
0824:                    if ((!isRightOriented && !isRightToLeft)
0825:                            || (isRightOriented && isRightToLeft)) {
0826:                        caretX = renderPositions[visualOffset]
0827:                                + dx[visualOffset];
0828:                    } else {
0829:                        caretX = renderPositions[visualOffset];
0830:                    }
0831:                } else
0832:                // consider local numbers as R2L in determining direction boundaries.
0833:                // fixes 1GK9API.
0834:                if (direction == ST.COLUMN_PREVIOUS
0835:                        && isRightToLeftInput(logicalOffset) != isRightToLeftInput(logicalOffset - 1)) {
0836:                    int visualOffset = order[logicalOffset];
0837:                    // moving between segments.
0838:                    // consider local numbers as R2L here, to determine position, because
0839:                    // we want to stay in L2R segment and place the cursor to the left of
0840:                    // first L2R character. see 1GK9API
0841:                    isRightToLeft = isRightToLeft(logicalOffset - 1);
0842:                    if ((!isRightOriented && !isRightToLeft)
0843:                            || (isRightOriented && isRightToLeft)) {
0844:                        caretX = renderPositions[visualOffset]
0845:                                + dx[visualOffset];
0846:                    } else {
0847:                        caretX = renderPositions[visualOffset];
0848:                    }
0849:                } else {
0850:                    int visualOffset = order[logicalOffset];
0851:                    if ((!isRightOriented && !isRightToLeft)
0852:                            || (isRightOriented && isRightToLeft)) {
0853:                        caretX = renderPositions[visualOffset];
0854:                    } else {
0855:                        caretX = renderPositions[visualOffset]
0856:                                + dx[visualOffset];
0857:                    }
0858:                }
0859:                return caretX;
0860:            }
0861:
0862:            /**
0863:             * Returns the width in pixels of the line.
0864:             * <p>
0865:             * 
0866:             * @return the width in pixels of the line.
0867:             */
0868:            int getTextWidth() {
0869:                int width = 0;
0870:
0871:                if (getTextLength() > 0) {
0872:                    width = renderPositions[renderPositions.length - 1]
0873:                            + dx[dx.length - 1];
0874:                }
0875:                return width;
0876:            }
0877:
0878:            /**
0879:             * Returns the visual offset of the character at the specified 
0880:             * logical offset.
0881:             * <p>
0882:             * 
0883:             * @param logicalOffset the logical offset
0884:             * @return the visual offset of the character at <code>logicalOffset</code>.
0885:             */
0886:            int getVisualOffset(int logicalOffset) {
0887:                return order[logicalOffset];
0888:            }
0889:
0890:            /**
0891:             * Returns the visual offset of the character at the specified x 
0892:             * location.
0893:             * <p>
0894:             * 
0895:             * @param x the location of the character
0896:             * @return the visual offset of the character at the specified x 
0897:             * 	location.
0898:             */
0899:            private int getVisualOffsetAtX(int x) {
0900:                int lineLength = getTextLength();
0901:                int low = -1;
0902:                int high = lineLength;
0903:
0904:                while (high - low > 1) {
0905:                    int offset = (high + low) / 2;
0906:                    int visualX = renderPositions[offset];
0907:
0908:                    // visualX + dx is the start of the next character. Restrict right/high
0909:                    // search boundary only if x is before next character. Fixes 1GL4ZVE.
0910:                    if (x < visualX + dx[offset]) {
0911:                        high = offset;
0912:                    } else if (high == lineLength && high - offset == 1) {
0913:                        // requested x location is past end of line
0914:                        high = -1;
0915:                    } else {
0916:                        low = offset;
0917:                    }
0918:                }
0919:                return high;
0920:            }
0921:
0922:            /**
0923:             * Returns if the character at the given offset is a latin number.
0924:             * <p>
0925:             * 
0926:             * @param logicalIndex the index of the character 
0927:             * @return 
0928:             * 	true=the character at the specified index is a latin number
0929:             * 	false=the character at the specified index is not a latin number
0930:             */
0931:            boolean isLatinNumber(int logicalIndex) {
0932:                boolean isLatinNumber = false;
0933:
0934:                if (logicalIndex >= 0 && logicalIndex < classBuffer.length) {
0935:                    isLatinNumber = classBuffer[logicalIndex] == BidiUtil.CLASS_EUROPEAN_NUMBER;
0936:                }
0937:                return isLatinNumber;
0938:            }
0939:
0940:            /**
0941:             * Returns if the character at the given offset is a local number.
0942:             * <p>
0943:             * 
0944:             * @param logicalIndex the index of the character 
0945:             * @return 
0946:             * 	true=the character at the specified index is a local number
0947:             * 	false=the character at the specified index is not a local number
0948:             */
0949:            boolean isLocalNumber(int logicalIndex) {
0950:                boolean isLocalNumber = false;
0951:
0952:                if (logicalIndex >= 0 && logicalIndex < classBuffer.length) {
0953:                    isLocalNumber = classBuffer[logicalIndex] == BidiUtil.CLASS_ARABIC_NUMBER;
0954:                }
0955:                return isLocalNumber;
0956:            }
0957:
0958:            /**
0959:             * Returns the direction of the character at the specified index.
0960:             * Used for rendering and caret positioning where local numbers (e.g., 
0961:             * national Arabic, or Hindi, numbers) are considered left-to-right.
0962:             * <p>
0963:             * 
0964:             * @param logicalIndex the index of the character
0965:             * @return 
0966:             * 	true=the character at the specified index is in a right-to-left
0967:             * 	codepage (e.g., Hebrew, Arabic).
0968:             * 	false=the character at the specified index is in a left-to-right/latin
0969:             * 	codepage.
0970:             */
0971:            boolean isRightToLeft(int logicalIndex) {
0972:                boolean isRightToLeft = false;
0973:
0974:                if (logicalIndex >= 0 && logicalIndex < classBuffer.length) {
0975:                    isRightToLeft = (classBuffer[logicalIndex] == BidiUtil.CLASS_RTL_ARABIC)
0976:                            || (classBuffer[logicalIndex] == BidiUtil.CLASS_RTL);
0977:                }
0978:                return isRightToLeft;
0979:            }
0980:
0981:            /**
0982:             * Returns the direction of the character at the specified index.
0983:             * Used for setting the keyboard language where local numbers (e.g., 
0984:             * national Arabic, or Hindi, numbers) are considered right-to-left.
0985:             * <p>
0986:             * 
0987:             * @param logicalIndex the index of the character
0988:             * @return 
0989:             * 	true=the character at the specified index is in a right-to-left
0990:             * 	codepage (e.g., Hebrew, Arabic).
0991:             * 	false=the character at the specified index is in a left-to-right/latin
0992:             * 	codepage.
0993:             */
0994:            boolean isRightToLeftInput(int logicalIndex) {
0995:                boolean isRightToLeft = false;
0996:
0997:                if (logicalIndex >= 0 && logicalIndex < classBuffer.length) {
0998:                    isRightToLeft = (classBuffer[logicalIndex] == BidiUtil.CLASS_RTL_ARABIC)
0999:                            || (classBuffer[logicalIndex] == BidiUtil.CLASS_RTL)
1000:                            || (classBuffer[logicalIndex] == BidiUtil.CLASS_ARABIC_NUMBER);
1001:                }
1002:                return isRightToLeft;
1003:            }
1004:
1005:            /**
1006:             * Returns whether the specified index is the start of a user 
1007:             * specified direction segment.
1008:             * <p>
1009:             * 
1010:             * @param logicalIndex the index to test
1011:             * @return true=the specified index is the start of a user specified 
1012:             * 	direction segment, false otherwise
1013:             */
1014:            private boolean isStartOfBidiSegment(int logicalIndex) {
1015:                for (int i = 0; i < bidiSegments.length; i++) {
1016:                    if (bidiSegments[i] == logicalIndex)
1017:                        return true;
1018:                }
1019:                return false;
1020:            }
1021:
1022:            /**
1023:             * Reorders and calculates render positions for the specified sub-line 
1024:             * of text. The results will be merged with the data for the rest of 
1025:             * the line .
1026:             * <p>
1027:             * 
1028:             * @param textline the entire line of text that this object represents.
1029:             * @param logicalStart the start offset of the first character to 
1030:             * 	reorder.
1031:             * @param length the number of characters to reorder
1032:             */
1033:            private void prepareFontStyledText(String textline,
1034:                    int logicalStart, int length) {
1035:                int byteCount = length;
1036:                int flags = 0;
1037:                String text = textline.substring(logicalStart, logicalStart
1038:                        + length);
1039:
1040:                // Figure out what is before and after the substring so that the proper character 
1041:                // shaping will occur.  Character shaping will not occur across bidi segments, so
1042:                // if the styled text starts or ends on a bidi segment, do not process the text
1043:                // for character shaping.
1044:                if (logicalStart != 0
1045:                        && isCharacterShaped(gc)
1046:                        && !isStartOfBidiSegment(logicalStart)
1047:                        && !Compatibility.isWhitespace(textline
1048:                                .charAt(logicalStart - 1))
1049:                        && isRightToLeft(logicalStart - 1)) {
1050:                    // if the start of the substring is not the beginning of the 
1051:                    // text line, check to see what is before the string
1052:                    flags |= BidiUtil.LINKBEFORE;
1053:                }
1054:                if ((logicalStart + byteCount) != dx.length
1055:                        && isCharacterShaped(gc)
1056:                        && !isStartOfBidiSegment(logicalStart + length)
1057:                        && !Compatibility.isWhitespace(textline
1058:                                .charAt(logicalStart + byteCount))
1059:                        && isRightToLeft(logicalStart + byteCount)) {
1060:                    // if the end of the substring is not the end of the text line,
1061:                    // check to see what is after the substring
1062:                    flags |= BidiUtil.LINKAFTER;
1063:                }
1064:                // set classification values for the substring
1065:                flags |= BidiUtil.CLASSIN;
1066:                byte[] classArray = new byte[byteCount];
1067:                int[] renderIndexes = getRenderIndexesFor(logicalStart,
1068:                        byteCount);
1069:                for (int i = 0; i < byteCount; i++) {
1070:                    classArray[i] = classBuffer[renderIndexes[i]];
1071:                }
1072:                int[] dxArray = new int[byteCount];
1073:                int[] orderArray = new int[byteCount];
1074:                char[] boldGlyphBuffer;
1075:                boldGlyphBuffer = BidiUtil.getRenderInfo(gc, text, orderArray,
1076:                        classArray, dxArray, flags, new int[] { 0,
1077:                                text.length() });
1078:                // update the existing dx/glyph arrays with the new values based on the bold font
1079:                for (int i = 0; i < dxArray.length; i++) {
1080:                    int index = orderArray[i];
1081:                    int visualIndex = renderIndexes[i];
1082:                    dx[visualIndex] = dxArray[index];
1083:                    glyphBuffer[visualIndex] = boldGlyphBuffer[index];
1084:                }
1085:            }
1086:
1087:            /** 
1088:             * Redraws a rectangle spanning the given logical range.
1089:             * The rectangle may be visually discontiguous if the text segment 
1090:             * is bidirectional.
1091:             * <p>
1092:             * 
1093:             * @param parent window that should be invalidated
1094:             * @param logicalStart logcial start offset of the rectangle
1095:             * @param length number of logical characters the rectangle should span
1096:             * @param xOffset x location of the line start
1097:             * @param yOffset y location of the line start
1098:             * @param height height of the invalidated rectangle
1099:             */
1100:            void redrawRange(Control parent, int logicalStart, int length,
1101:                    int xOffset, int yOffset, int height) {
1102:                Enumeration directionRuns;
1103:                if (logicalStart < 0 || logicalStart + length > getTextLength()) {
1104:                    return;
1105:                }
1106:                directionRuns = getDirectionRuns(logicalStart, length)
1107:                        .elements();
1108:                while (directionRuns.hasMoreElements()) {
1109:                    DirectionRun run = (DirectionRun) directionRuns
1110:                            .nextElement();
1111:                    int startX = run.getRenderStartX();
1112:                    int endX = run.getRenderStopX();
1113:                    int runStartOffset = run.getVisualStart();
1114:                    int runEndOffset = run.getVisualEnd();
1115:
1116:                    // expand the redraw area by one character in both directions.
1117:                    // fixes bug 40019 		
1118:                    if (runStartOffset > 0) {
1119:                        startX = renderPositions[runStartOffset - 1];
1120:                    } else {
1121:                        startX = 0;
1122:                    }
1123:                    if (runEndOffset < renderPositions.length - 1) {
1124:                        endX = renderPositions[runEndOffset + 1]
1125:                                + dx[runEndOffset + 1];
1126:                    }
1127:                    parent.redraw(xOffset + startX, yOffset, endX - startX,
1128:                            height, true);
1129:                }
1130:            }
1131:
1132:            /**
1133:             * Sets the keyboard language to match the codepage of the character 
1134:             * at the specified offset.
1135:             * Only distinguishes between left-to-right and right-to-left characters and 
1136:             * sets the keyboard language to a bidi or non-bidi language.
1137:             * <p>
1138:             * 
1139:             * @param logicalIndex logical offset of the character to use for 
1140:             * 	determining the new keyboard language.
1141:             */
1142:            void setKeyboardLanguage(int logicalIndex) {
1143:                int language;
1144:                int current = BidiUtil.getKeyboardLanguage();
1145:
1146:                if (logicalIndex < 0 || logicalIndex >= classBuffer.length) {
1147:                    return;
1148:                }
1149:                if (isRightToLeftInput(logicalIndex)) {
1150:                    // keyboard already in bidi mode, since we cannot distinguish between
1151:                    // multiple bidi languages, just return
1152:                    if (current == BidiUtil.KEYBOARD_BIDI)
1153:                        return;
1154:                    language = BidiUtil.KEYBOARD_BIDI;
1155:                } else {
1156:                    // keyboard already in non-bidi mode, since we cannot distinguish between
1157:                    // multiple non-bidi languages, just return
1158:                    if (current == BidiUtil.KEYBOARD_NON_BIDI)
1159:                        return;
1160:                    language = BidiUtil.KEYBOARD_NON_BIDI;
1161:                }
1162:                BidiUtil.setKeyboardLanguage(language);
1163:            }
1164:
1165:            /**
1166:             * Sets the orientation (writing order) of the specified control. Text will 
1167:             * be right aligned for right to left writing order.
1168:             * <p>
1169:             * 
1170:             * @param orientation one of SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT
1171:             * @return true if the orientation was changed, false if the orientation 
1172:             * 	could not be changed
1173:             */
1174:            static boolean setOrientation(Control control, int orientation) {
1175:                return BidiUtil.setOrientation(control.handle, orientation);
1176:            }
1177:
1178:            /**
1179:             * Returns a string representation of the receiver.
1180:             * <p>
1181:             * 
1182:             * @return a string representation of the receiver for 
1183:             *	debugging purposes. The output order of the StyledTextbidi values
1184:             *	is as follows: order, render position, dx, character class, glyphs.
1185:             */
1186:            public String toString() {
1187:                StringBuffer buf = new StringBuffer();
1188:
1189:                buf.append("StyledTextBidi {{");
1190:                // order
1191:                for (int i = 0; i < order.length; i++) {
1192:                    if (i != 0) {
1193:                        buf.append(",");
1194:                    }
1195:                    buf.append(order[i]);
1196:                }
1197:                buf.append("}, {");
1198:                // render positions
1199:                for (int i = 0; i < renderPositions.length; i++) {
1200:                    if (i != 0) {
1201:                        buf.append(",");
1202:                    }
1203:                    buf.append(renderPositions[i]);
1204:                }
1205:                buf.append("}, {");
1206:                // dx
1207:                for (int i = 0; i < dx.length; i++) {
1208:                    if (i != 0) {
1209:                        buf.append(",");
1210:                    }
1211:                    buf.append(dx[i]);
1212:                }
1213:                buf.append("}, {");
1214:                // character class
1215:                for (int i = 0; i < classBuffer.length; i++) {
1216:                    if (i != 0) {
1217:                        buf.append(",");
1218:                    }
1219:                    buf.append(classBuffer[i]);
1220:                }
1221:                buf.append("}, {");
1222:                // glyphs
1223:                buf.append(glyphBuffer);
1224:                buf.append("}}");
1225:                return buf.toString();
1226:            }
1227:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.