Source Code Cross Referenced for BidiParagraphRenderer.java in  » Internationalization-Localization » icu4j » com » ibm » richtext » textformat » 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 » Internationalization Localization » icu4j » com.ibm.richtext.textformat 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * (C) Copyright IBM Corp. 1998-2004.  All Rights Reserved.
0003:         *
0004:         * The program is provided "as is" without any warranty express or
0005:         * implied, including the warranty of non-infringement and the implied
0006:         * warranties of merchantibility and fitness for a particular purpose.
0007:         * IBM will not be liable for any damages suffered by you as a result
0008:         * of using the Program. In no event will IBM be liable for any
0009:         * special, indirect or consequential damages or lost profits even if
0010:         * IBM has been advised of the possibility of their occurrence. IBM
0011:         * will not be liable for any third party claims against you.
0012:         */
0013:        // Requires Java2
0014:        package com.ibm.richtext.textformat;
0015:
0016:        import java.awt.Color;
0017:        import java.awt.Rectangle;
0018:        import java.awt.Shape;
0019:
0020:        import java.util.Vector;
0021:
0022:        import com.ibm.richtext.styledtext.MConstText;
0023:        import com.ibm.richtext.styledtext.MTabRuler;
0024:        import com.ibm.richtext.styledtext.TabStop;
0025:
0026:        import com.ibm.richtext.textlayout.attributes.AttributeMap;
0027:        import com.ibm.richtext.textlayout.attributes.TextAttribute;
0028:
0029:        import com.ibm.richtext.textlayout.Graphics2DConversion;
0030:
0031:        ///*JDK12IMPORTS
0032:        import java.awt.Graphics2D;
0033:
0034:        import java.awt.font.FontRenderContext;
0035:        import java.awt.font.TextLayout;
0036:        import java.awt.font.LineBreakMeasurer;
0037:        import java.awt.font.TextHitInfo;
0038:
0039:        import java.awt.geom.AffineTransform;
0040:        import java.awt.geom.GeneralPath;
0041:        import java.awt.geom.Rectangle2D;
0042:
0043:        //JDK12IMPORTS*/
0044:        /*JDK11IMPORTS
0045:         import com.ibm.richtext.textlayout.Graphics2D;
0046:
0047:         import com.ibm.richtext.textlayout.FontRenderContext;
0048:         import com.ibm.richtext.textlayout.TextLayout;
0049:         import com.ibm.richtext.textlayout.LineBreakMeasurer;
0050:         import com.ibm.richtext.textlayout.TextHitInfo;
0051:
0052:         import com.ibm.richtext.textlayout.AffineTransform;
0053:         import com.ibm.richtext.textlayout.GeneralPath;
0054:         import com.ibm.richtext.textlayout.Rectangle2D;
0055:         JDK11IMPORTS*/
0056:
0057:        final class BidiParagraphRenderer extends ParagraphRenderer {
0058:
0059:            static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
0060:
0061:            private final class BidiSegment {
0062:                TextLayout fLayout;
0063:                Rectangle2D.Float fBounds;
0064:                int fDistanceFromLeadingMargin;
0065:            }
0066:
0067:            private final class BidiLayoutInfo extends LayoutInfo {
0068:                int fCharLength; // number of characters on line (was fLength)
0069:                int fAscent;
0070:                int fDescent;
0071:                int fLeading;
0072:                int fVisibleAdvance; // distance along line direction ie width
0073:                int fTotalAdvance; // distance along line direction including trailing whitespace
0074:
0075:                int fLeadingMargin; // screen distance from leading margin
0076:
0077:                boolean fLeftToRight; // true iff the orientation is left-to-right
0078:
0079:                final Vector fSegments = new Vector(); // segments to render, in logical order
0080:
0081:                public int getCharLength() {
0082:                    return fCharLength;
0083:                }
0084:
0085:                public int getAscent() {
0086:                    return fAscent;
0087:                }
0088:
0089:                public int getDescent() {
0090:                    return fDescent;
0091:                }
0092:
0093:                public int getLeading() {
0094:                    return fLeading;
0095:                }
0096:
0097:                public int getVisibleAdvance() {
0098:                    return fVisibleAdvance;
0099:                }
0100:
0101:                public int getTotalAdvance() {
0102:                    return fTotalAdvance;
0103:                }
0104:
0105:                public int getLeadingMargin() {
0106:                    return fLeadingMargin;
0107:                }
0108:
0109:                public boolean isLeftToRight() {
0110:                    return fLeftToRight;
0111:                }
0112:
0113:                public int getHeight() {
0114:                    return fAscent + fDescent + fLeading;
0115:                }
0116:
0117:                public String toString() {
0118:                    return "LayoutInfo(charStart: " + getCharStart(0)
0119:                            + ", fCharLength: " + fCharLength + ", fAscent: "
0120:                            + fAscent + ", fDescent: " + fDescent
0121:                            + ", fVisibleAdvance: " + fVisibleAdvance
0122:                            + ", fTotalAdvance: " + fTotalAdvance
0123:                            + ", fLeadingMargin: " + fLeadingMargin + ")";
0124:                }
0125:
0126:                BidiParagraphRenderer fRenderer;
0127:
0128:                // just delegate to renderer for now
0129:
0130:                public void renderWithHighlight(int lengthBasis, Graphics2D g,
0131:                        int lineBound, int x, int y, TextOffset selStart,
0132:                        TextOffset selStop, Color highlightColor) {
0133:
0134:                    fRenderer.renderWithHighlight(this , lengthBasis, g,
0135:                            lineBound, x, y, selStart, selStop, highlightColor);
0136:                }
0137:
0138:                public void render(int lengthBasis, Graphics2D g,
0139:                        int lineBound, int x, int y) {
0140:                    fRenderer.render(this , lengthBasis, g, lineBound, x, y);
0141:                }
0142:
0143:                public void renderCaret(MConstText text, int lengthBasis,
0144:                        Graphics2D g, int lineBound, int x, int y,
0145:                        int charOffset, Color strongCaretColor,
0146:                        Color weakCaretColor) {
0147:                    fRenderer.renderCaret(this , text, lengthBasis, g,
0148:                            lineBound, x, y, charOffset, strongCaretColor,
0149:                            weakCaretColor);
0150:                }
0151:
0152:                public TextOffset pixelToOffset(int lengthBasis,
0153:                        TextOffset result, int lineBound, int x, int y) {
0154:                    return fRenderer.pixelToOffset(this , lengthBasis, result,
0155:                            lineBound, x, y);
0156:                }
0157:
0158:                public Rectangle caretBounds(MConstText text, int lengthBasis,
0159:                        int lineBound, int charOffset, int x, int y) {
0160:                    return fRenderer.caretBounds(this , text, lengthBasis,
0161:                            lineBound, charOffset, x, y);
0162:                }
0163:
0164:                public int strongCaretBaselinePosition(int lengthBasis,
0165:                        int lineBound, int charOffset) {
0166:
0167:                    return fRenderer.strongCaretBaselinePosition(this ,
0168:                            lengthBasis, lineBound, charOffset);
0169:                }
0170:
0171:                public int getNextOffset(int lengthBasis, int charOffset,
0172:                        short dir) {
0173:
0174:                    return fRenderer.getNextOffset(this , lengthBasis,
0175:                            charOffset, dir);
0176:                }
0177:            }
0178:
0179:            private static final int FLUSH_LEADING = TextAttribute.FLUSH_LEADING
0180:                    .intValue();
0181:            private static final int FLUSH_CENTER = TextAttribute.FLUSH_CENTER
0182:                    .intValue();
0183:            private static final int FLUSH_TRAILING = TextAttribute.FLUSH_TRAILING
0184:                    .intValue();
0185:            private static final int FULLY_JUSTIFIED = TextAttribute.FULLY_JUSTIFIED
0186:                    .intValue();
0187:
0188:            private AttributeMap cacheStyle = null;
0189:
0190:            private float fLeadingMargin;
0191:            private float fTrailingMargin;
0192:            private float fFirstLineIndent;
0193:            private float fMinLineSpacing;
0194:            private float fExtraLineSpacing;
0195:
0196:            private int fFlush = -1;
0197:            private MTabRuler fTabRuler;
0198:
0199:            private boolean fLtrDefault;
0200:            private DefaultCharacterMetric fDefaultCharMetric;
0201:
0202:            BidiParagraphRenderer(AttributeMap pStyle,
0203:                    DefaultCharacterMetric defaultCharMetric) {
0204:
0205:                fDefaultCharMetric = defaultCharMetric;
0206:                initRenderer(pStyle);
0207:            }
0208:
0209:            private float getFloatValue(Object key, AttributeMap style) {
0210:                return ((Float) style.get(key)).floatValue();
0211:            }
0212:
0213:            private int getIntValue(Object key, AttributeMap style) {
0214:                return ((Integer) style.get(key)).intValue();
0215:            }
0216:
0217:            /**
0218:             * NOTE:  it is illegal to initialize a StandardParagraphRenderer for any style
0219:             * other than the one it was created with.
0220:             */
0221:            public void initRenderer(AttributeMap pStyle) {
0222:
0223:                if (cacheStyle == null) {
0224:
0225:                    fLeadingMargin = getFloatValue(
0226:                            TextAttribute.LEADING_MARGIN, pStyle);
0227:                    fTrailingMargin = getFloatValue(
0228:                            TextAttribute.TRAILING_MARGIN, pStyle);
0229:                    fFirstLineIndent = getFloatValue(
0230:                            TextAttribute.FIRST_LINE_INDENT, pStyle);
0231:                    fMinLineSpacing = getFloatValue(
0232:                            TextAttribute.MIN_LINE_SPACING, pStyle);
0233:                    fExtraLineSpacing = getFloatValue(
0234:                            TextAttribute.EXTRA_LINE_SPACING, pStyle);
0235:
0236:                    fFlush = getIntValue(TextAttribute.LINE_FLUSH, pStyle);
0237:
0238:                    fTabRuler = (MTabRuler) pStyle.get(TextAttribute.TAB_RULER);
0239:
0240:                    Object runDir = pStyle.get(TextAttribute.RUN_DIRECTION);
0241:                    fLtrDefault = !TextAttribute.RUN_DIRECTION_RTL
0242:                            .equals(runDir);
0243:
0244:                    cacheStyle = pStyle;
0245:                } else if (pStyle != cacheStyle) {
0246:                    if (!pStyle.equals(cacheStyle)) {
0247:                        throw new Error(
0248:                                "Attempt to share BidiParagraphRenderer between styles!");
0249:                    } else {
0250:                        cacheStyle = pStyle;
0251:                    }
0252:                }
0253:            }
0254:
0255:            private static boolean isTab(char ch) {
0256:                return ch == '\t';
0257:            }
0258:
0259:            /**
0260:             * Fill in info with the next line.
0261:             * @param measurer the LineBreakMeasurer for this paragraph.
0262:             *  Current position should be the first character on the line.
0263:             *  If null, a 0-length line is generated.  If measurer is null
0264:             *  then paragraphStart and paragraphLimit should be equal.
0265:             */
0266:            // Usually totalFormatWidth and lineBound will be the same.
0267:            // totalFormatWidth is used for wrapping, but lineBound is
0268:            // for flushing.  These may be different for unwrapped text,
0269:            // for example.
0270:            public LayoutInfo layout(MConstText text, LayoutInfo layoutToReuse,
0271:                    LineBreakMeasurer measurer, FontRenderContext frc,
0272:                    int paragraphStart, int paragraphLimit,
0273:                    int totalFormatWidth, int lineBound) {
0274:
0275:                if ((measurer == null) != (paragraphStart == paragraphLimit)) {
0276:                    throw new IllegalArgumentException(
0277:                            "measurer, paragraphStart, paragraphLimit are wrong.");
0278:                }
0279:                BidiLayoutInfo line = null;
0280:
0281:                try {
0282:                    line = (BidiLayoutInfo) layoutToReuse;
0283:                } catch (ClassCastException e) {
0284:                }
0285:
0286:                if (line == null) {
0287:                    line = new BidiLayoutInfo();
0288:                }
0289:
0290:                line.fRenderer = this ;
0291:
0292:                final int lineCharStart = measurer == null ? paragraphStart
0293:                        : measurer.getPosition();
0294:                line.setCharStart(lineCharStart);
0295:
0296:                final int lineIndent = (lineCharStart == paragraphStart) ? (int) fFirstLineIndent
0297:                        : 0;
0298:
0299:                int formatWidth = totalFormatWidth
0300:                        - (int) (fLeadingMargin + fTrailingMargin);
0301:                computeLineMetrics(text, line, measurer, frc, paragraphStart,
0302:                        paragraphLimit, formatWidth, lineIndent);
0303:
0304:                // position the line according to the line flush
0305:                if (fFlush == FLUSH_TRAILING || fFlush == FLUSH_CENTER) {
0306:                    int lineArea = lineBound
0307:                            - (int) (fLeadingMargin + fTrailingMargin);
0308:                    int advanceDifference = lineArea - line.fVisibleAdvance;
0309:
0310:                    if (fFlush == FLUSH_TRAILING) {
0311:                        line.fLeadingMargin = ((int) (fLeadingMargin))
0312:                                + advanceDifference;
0313:                    } else if (fFlush == FLUSH_CENTER) {
0314:                        line.fLeadingMargin = (int) (fLeadingMargin + advanceDifference / 2);
0315:                    }
0316:                } else {
0317:                    line.fLeadingMargin = (int) fLeadingMargin;
0318:                }
0319:
0320:                return line;
0321:            }
0322:
0323:            /**
0324:             * Fill in the following fields in line:
0325:             * fCharLength, fAscent, fDescent, fLeading, fVisibleAdvance,
0326:             * fTotalAdvance.
0327:             * Uses: line.fLeadingMargin
0328:             * @param formatWidth the width to fit the line into.
0329:             */
0330:            private void computeLineMetrics(MConstText text,
0331:                    BidiLayoutInfo line, LineBreakMeasurer measurer,
0332:                    FontRenderContext frc, final int paragraphStart,
0333:                    final int paragraphLimit, final int formatWidth,
0334:                    final int lineIndent) {
0335:
0336:                int segmentCount = 0;
0337:                /* variable not used boolean firstLine = measurer==null ||
0338:                                    measurer.getPosition() == paragraphStart; */
0339:
0340:                if (measurer != null) {
0341:                    computeSegments(text, line, measurer, paragraphLimit,
0342:                            formatWidth, lineIndent);
0343:
0344:                    // iterate through segments and accumulate ascent, descent,
0345:                    // leading, char length
0346:                    float ascent = 0;
0347:                    float descent = 0;
0348:                    float descentPlusLeading = 0;
0349:
0350:                    segmentCount = line.fSegments.size();
0351:                    for (int i = 0; i < segmentCount; i++) {
0352:                        TextLayout layout = ((BidiSegment) line.fSegments
0353:                                .elementAt(i)).fLayout;
0354:                        ascent = Math.max(ascent, layout.getAscent());
0355:                        float segDescent = layout.getDescent();
0356:                        descent = Math.max(descent, segDescent);
0357:                        descentPlusLeading = Math.max(descentPlusLeading,
0358:                                segDescent + layout.getLeading());
0359:                        line.fCharLength += layout.getCharacterCount();
0360:                    }
0361:
0362:                    line.fAscent = (int) Math.ceil(ascent);
0363:                    line.fDescent = (int) Math.ceil(descent);
0364:                    line.fLeading = (int) Math.ceil(descentPlusLeading)
0365:                            - line.fDescent;
0366:                } else {
0367:                    line.fLeftToRight = fLtrDefault;
0368:                    line.fSegments.removeAllElements();
0369:
0370:                    line.fCharLength = 0;
0371:
0372:                    AttributeMap style = text.characterStyleAt(paragraphStart);
0373:                    DefaultCharacterMetric.Metric cm = fDefaultCharMetric
0374:                            .getMetricForStyle(style);
0375:                    line.fAscent = cm.getAscent();
0376:                    line.fDescent = cm.getDescent();
0377:                    line.fLeading = cm.getLeading();
0378:
0379:                    line.fVisibleAdvance = line.fTotalAdvance = 0;
0380:                }
0381:
0382:                if (fExtraLineSpacing != 0) {
0383:                    line.fAscent += (int) Math.ceil(fExtraLineSpacing);
0384:                }
0385:
0386:                if (fMinLineSpacing != 0) {
0387:                    int height = line.getHeight();
0388:                    if (height < fMinLineSpacing) {
0389:                        line.fAscent += Math.ceil(fMinLineSpacing - height);
0390:                    }
0391:                }
0392:
0393:                final int lineNaturalAdvance = line.fTotalAdvance;
0394:
0395:                line.fTotalAdvance += lineIndent;
0396:                line.fVisibleAdvance += lineIndent;
0397:
0398:                if (measurer != null) {
0399:                    // Now fill in fBounds field of BidiSegments.  fBounds should tile
0400:                    // the line.
0401:                    final float lineHeight = line.getHeight();
0402:
0403:                    for (int i = 1; i < segmentCount; i++) {
0404:
0405:                        BidiSegment currentSegment = (BidiSegment) line.fSegments
0406:                                .elementAt(i - 1);
0407:                        BidiSegment nextSegment = (BidiSegment) line.fSegments
0408:                                .elementAt(i);
0409:
0410:                        float origin;
0411:                        float width;
0412:
0413:                        if (line.fLeftToRight) {
0414:                            origin = 0;
0415:                            width = nextSegment.fDistanceFromLeadingMargin
0416:                                    - currentSegment.fDistanceFromLeadingMargin;
0417:                        } else {
0418:                            origin = currentSegment.fDistanceFromLeadingMargin;
0419:                            origin -= nextSegment.fDistanceFromLeadingMargin;
0420:                            origin += (float) Math.ceil(nextSegment.fLayout
0421:                                    .getAdvance());
0422:                            width = (float) Math.ceil(currentSegment.fLayout
0423:                                    .getAdvance())
0424:                                    - origin;
0425:                        }
0426:                        currentSegment.fBounds = new Rectangle2D.Float(origin,
0427:                                -line.fAscent, width, lineHeight);
0428:                    }
0429:
0430:                    // set last segment's bounds
0431:                    {
0432:                        BidiSegment currentSegment = (BidiSegment) line.fSegments
0433:                                .elementAt(segmentCount - 1);
0434:                        float origin;
0435:                        float width;
0436:
0437:                        if (line.fLeftToRight) {
0438:                            origin = 0;
0439:                            width = lineNaturalAdvance
0440:                                    - currentSegment.fDistanceFromLeadingMargin;
0441:                        } else {
0442:                            origin = currentSegment.fDistanceFromLeadingMargin
0443:                                    - lineNaturalAdvance;
0444:                            width = (float) Math.ceil(currentSegment.fLayout
0445:                                    .getAdvance())
0446:                                    - origin;
0447:                        }
0448:
0449:                        currentSegment.fBounds = new Rectangle2D.Float(origin,
0450:                                -line.fAscent, width, lineHeight);
0451:                    }
0452:                }
0453:            }
0454:
0455:            /**
0456:             * Fill in fSegments, fLeftToRight.  measurer must not be null
0457:             */
0458:            private void computeSegments(MConstText text, BidiLayoutInfo line,
0459:                    LineBreakMeasurer measurer, final int paragraphLimit,
0460:                    final int formatWidth, final int lineIndent) {
0461:
0462:                // Note on justification:  only the last segment of a line is
0463:                // justified.  
0464:                // Also, if a line ends in a tab it will not be justified.
0465:                // This behavior is consistent with other word processors
0466:                // I tried (MS Word and Lotus Word Pro).
0467:
0468:                line.fSegments.removeAllElements();
0469:                line.fCharLength = 0;
0470:
0471:                TabStop currentTabStop = new TabStop((int) fLeadingMargin
0472:                        + lineIndent, TabStop.kLeading);
0473:
0474:                int segmentLimit = measurer.getPosition();
0475:                boolean firstSegment = true;
0476:
0477:                int advanceFromLeadingMargin = lineIndent;
0478:
0479:                boolean computeSegs = true;
0480:
0481:                computeTabbedSegments: do {
0482:
0483:                    // compute sementLimit:
0484:                    if (segmentLimit <= measurer.getPosition()) {
0485:                        while (segmentLimit < paragraphLimit) {
0486:                            if (isTab(text.at(segmentLimit++))) {
0487:                                break;
0488:                            }
0489:                        }
0490:                    }
0491:
0492:                    // NOTE:  adjust available width for center tab!!!
0493:                    //System.out.println("Format width: " + (formatWidth-advanceFromLeadingMargin) +
0494:                    //                   ";  segmentLimit: " + segmentLimit);
0495:
0496:                    int wrappingWidth = Math.max(formatWidth
0497:                            - advanceFromLeadingMargin, 0);
0498:                    TextLayout layout = null;
0499:                    if (firstSegment || wrappingWidth > 0
0500:                            || segmentLimit > measurer.getPosition() + 1) {
0501:                        layout = measurer.nextLayout(wrappingWidth,
0502:                                segmentLimit, !firstSegment);
0503:                    }
0504:
0505:                    if (layout == null) {
0506:                        if (firstSegment) {
0507:                            // I doubt this would happen, but check anyway
0508:                            throw new Error("First layout is null!");
0509:                        }
0510:                        break computeTabbedSegments;
0511:                    }
0512:
0513:                    final int measurerPos = measurer.getPosition();
0514:                    if (measurerPos < segmentLimit) {
0515:                        computeSegs = false;
0516:                        if (fFlush == FULLY_JUSTIFIED) {
0517:                            layout = layout.getJustifiedLayout(wrappingWidth);
0518:                        }
0519:                    } else {
0520:                        computeSegs = !(measurerPos == paragraphLimit);
0521:                    }
0522:
0523:                    if (firstSegment) {
0524:                        firstSegment = false;
0525:                        // Have to get ltr off of layout.  Not available from measurer,
0526:                        // unfortunately.
0527:                        line.fLeftToRight = layout.isLeftToRight();
0528:                    }
0529:
0530:                    BidiSegment segment = new BidiSegment();
0531:                    segment.fLayout = layout;
0532:                    int layoutAdvance = (int) Math.ceil(layout.getAdvance());
0533:
0534:                    // position layout relative to leading margin, update logicalPositionOnLine
0535:
0536:                    int relativeTabPosition = currentTabStop.getPosition()
0537:                            - (int) fLeadingMargin;
0538:                    int logicalPositionOfLayout;
0539:                    switch (currentTabStop.getType()) {
0540:                    case TabStop.kTrailing:
0541:                        logicalPositionOfLayout = Math.max(relativeTabPosition
0542:                                - layoutAdvance, advanceFromLeadingMargin);
0543:                        break;
0544:                    case TabStop.kCenter:
0545:                        logicalPositionOfLayout = Math
0546:                                .max(relativeTabPosition - (layoutAdvance / 2),
0547:                                        advanceFromLeadingMargin);
0548:                        break;
0549:                    default: // includes decimal tab right now
0550:                        logicalPositionOfLayout = relativeTabPosition;
0551:                        break;
0552:                    }
0553:
0554:                    // position layout in segment
0555:                    if (line.fLeftToRight) {
0556:                        segment.fDistanceFromLeadingMargin = logicalPositionOfLayout;
0557:                    } else {
0558:                        segment.fDistanceFromLeadingMargin = logicalPositionOfLayout
0559:                                + layoutAdvance;
0560:                    }
0561:
0562:                    // update advanceFromLeadingMargin
0563:                    advanceFromLeadingMargin = logicalPositionOfLayout
0564:                            + layoutAdvance;
0565:
0566:                    // add segment to segment Vector
0567:                    line.fSegments.addElement(segment);
0568:
0569:                    // get next tab
0570:                    currentTabStop = fTabRuler.nextTab((int) fLeadingMargin
0571:                            + advanceFromLeadingMargin);
0572:                    if (currentTabStop.getType() == TabStop.kLeading
0573:                            || currentTabStop.getType() == TabStop.kAuto) {
0574:                        advanceFromLeadingMargin = currentTabStop.getPosition();
0575:                        //System.out.println("Advance from leading margin:" + advanceFromLeadingMargin);
0576:
0577:                    } else {
0578:                        //System.out.println("Non-leading tab, type=" + currentTabStop.getType());
0579:                    }
0580:
0581:                } while (computeSegs);
0582:
0583:                // Now compute fTotalAdvance, fVisibleAdvance.  These metrics may be affected
0584:                // by a trailing tab.
0585:
0586:                {
0587:                    BidiSegment lastSegment = (BidiSegment) line.fSegments
0588:                            .lastElement();
0589:                    TextLayout lastLayout = lastSegment.fLayout;
0590:
0591:                    if (line.fLeftToRight) {
0592:                        line.fTotalAdvance = (int) Math.ceil(lastLayout
0593:                                .getAdvance())
0594:                                + lastSegment.fDistanceFromLeadingMargin;
0595:                        line.fVisibleAdvance = (int) Math.ceil(lastLayout
0596:                                .getVisibleAdvance())
0597:                                + lastSegment.fDistanceFromLeadingMargin;
0598:                    } else {
0599:                        line.fTotalAdvance = lastSegment.fDistanceFromLeadingMargin;
0600:                        line.fVisibleAdvance = lastSegment.fDistanceFromLeadingMargin
0601:                                - (int) Math.ceil(lastLayout.getAdvance()
0602:                                        - lastLayout.getVisibleAdvance());
0603:                    }
0604:
0605:                    if (isTab(text.at(measurer.getPosition() - 1))) {
0606:                        line.fTotalAdvance = Math.max(line.fTotalAdvance,
0607:                                currentTabStop.getPosition());
0608:                    }
0609:                }
0610:            }
0611:
0612:            /**
0613:             * Return the highlight shape for the given character offsets.
0614:             * The Shape returned is relative to the leftmost point on the
0615:             * baseline of line.
0616:             */
0617:            private Shape getHighlightShape(BidiLayoutInfo line,
0618:                    int lengthBasis, int lineBound, int hlStart, int hlLimit) {
0619:
0620:                if (hlStart >= hlLimit) {
0621:                    throw new IllegalArgumentException(
0622:                            "Highlight range length is not positive.");
0623:                }
0624:
0625:                final int leadingMargin = (line.fLeftToRight) ? line.fLeadingMargin
0626:                        : lineBound - line.fLeadingMargin;
0627:                final int segmentCount = line.fSegments.size();
0628:
0629:                Shape rval = null;
0630:                GeneralPath highlightPath = null;
0631:
0632:                int currentLayoutStart = line.getCharStart(lengthBasis);
0633:
0634:                for (int i = 0; i < segmentCount; i++) {
0635:
0636:                    BidiSegment segment = (BidiSegment) line.fSegments
0637:                            .elementAt(i);
0638:                    TextLayout layout = segment.fLayout;
0639:                    int charCount = layout.getCharacterCount();
0640:                    int currentLayoutLimit = currentLayoutStart + charCount;
0641:                    boolean rangesIntersect;
0642:                    if (hlStart <= currentLayoutStart) {
0643:                        rangesIntersect = hlLimit > currentLayoutStart;
0644:                    } else {
0645:                        rangesIntersect = hlStart < currentLayoutLimit;
0646:                    }
0647:
0648:                    if (rangesIntersect) {
0649:
0650:                        Shape currentHl = layout.getLogicalHighlightShape(Math
0651:                                .max(hlStart - currentLayoutStart, 0), Math
0652:                                .min(hlLimit - currentLayoutStart, charCount),
0653:                                segment.fBounds);
0654:
0655:                        float xTranslate;
0656:                        if (line.fLeftToRight) {
0657:                            xTranslate = leadingMargin
0658:                                    + segment.fDistanceFromLeadingMargin;
0659:                        } else {
0660:                            xTranslate = leadingMargin
0661:                                    - segment.fDistanceFromLeadingMargin;
0662:                        }
0663:
0664:                        if (xTranslate != 0) {
0665:                            AffineTransform xform = AffineTransform
0666:                                    .getTranslateInstance(xTranslate, 0);
0667:                            currentHl = xform.createTransformedShape(currentHl);
0668:                        }
0669:
0670:                        if (rval == null) {
0671:                            rval = currentHl;
0672:                        } else {
0673:                            if (highlightPath == null) {
0674:                                highlightPath = new GeneralPath();
0675:                                highlightPath.append(rval, false);
0676:                                rval = highlightPath;
0677:                            }
0678:                            highlightPath.append(currentHl, false);
0679:                        }
0680:                    }
0681:                    currentLayoutStart = currentLayoutLimit;
0682:                }
0683:
0684:                return rval;
0685:            }
0686:
0687:            private void renderWithHighlight(BidiLayoutInfo line,
0688:                    int lengthBasis, Graphics2D g, int lineBound, int x, int y,
0689:                    TextOffset selStart, TextOffset selStop,
0690:                    Color highlightColor) {
0691:
0692:                final int lineCharStart = line.getCharStart(lengthBasis);
0693:
0694:                if (selStart != null && selStop != null
0695:                        && !selStart.equals(selStop) && line.fCharLength != 0
0696:                        && selStart.fOffset < lineCharStart + line.fCharLength
0697:                        && selStop.fOffset > lineCharStart) {
0698:
0699:                    Shape highlight = getHighlightShape(line, lengthBasis,
0700:                            lineBound, selStart.fOffset, selStop.fOffset);
0701:                    if (highlight != null) {
0702:                        Graphics2D hl = (Graphics2D) g.create();
0703:                        hl.setColor(highlightColor);
0704:                        hl.translate(x, y + line.fAscent);
0705:                        hl.fill(highlight);
0706:                    }
0707:                }
0708:
0709:                render(line, lengthBasis, g, lineBound, x, y);
0710:            }
0711:
0712:            /**
0713:             * Draw the line into the graphics.  (x, y) is the upper-left corner
0714:             * of the line.  The leading edge of a right-aligned line is aligned
0715:             * to (x + lineBound).
0716:             */
0717:            private void render(BidiLayoutInfo line, int lengthBasis,
0718:                    Graphics2D g, int lineBound, int x, int y) {
0719:
0720:                final int leadingMargin = (line.fLeftToRight) ? x
0721:                        + line.fLeadingMargin : x + lineBound
0722:                        - line.fLeadingMargin;
0723:                final int baseline = y + line.fAscent;
0724:                final int segmentCount = line.fSegments.size();
0725:
0726:                for (int i = 0; i < segmentCount; i++) {
0727:
0728:                    BidiSegment segment = (BidiSegment) line.fSegments
0729:                            .elementAt(i);
0730:
0731:                    float drawX;
0732:                    if (line.fLeftToRight) {
0733:                        drawX = leadingMargin
0734:                                + segment.fDistanceFromLeadingMargin;
0735:                    } else {
0736:                        drawX = leadingMargin
0737:                                - segment.fDistanceFromLeadingMargin;
0738:                    }
0739:
0740:                    segment.fLayout.draw(g, drawX, baseline);
0741:                }
0742:            }
0743:
0744:            private TextOffset hitTestSegment(TextOffset result,
0745:                    int segmentCharStart, BidiSegment segment, int xInSegment,
0746:                    int yInSegment) {
0747:
0748:                final TextLayout layout = segment.fLayout;
0749:                final int charCount = layout.getCharacterCount();
0750:                final int layoutAdvance = (int) Math.ceil(layout.getAdvance());
0751:                Rectangle2D bounds = segment.fBounds;
0752:
0753:                final boolean ltr = layout.isLeftToRight();
0754:
0755:                if (ltr && (xInSegment >= layoutAdvance) || !ltr
0756:                        && (xInSegment <= 0)) {
0757:
0758:                    // pretend the extra space at the end of the line is a
0759:                    // tab and 'hit-test' it.
0760:                    double tabCenter;
0761:                    if (ltr) {
0762:                        tabCenter = (layoutAdvance + bounds.getMaxX()) / 2;
0763:                    } else {
0764:                        tabCenter = bounds.getX() / 2;
0765:                    }
0766:
0767:                    if ((xInSegment >= tabCenter) == ltr) {
0768:                        result.fOffset = charCount;
0769:                        result.fPlacement = TextOffset.BEFORE_OFFSET;
0770:                    } else {
0771:                        result.fOffset = charCount - 1;
0772:                        result.fPlacement = TextOffset.AFTER_OFFSET;
0773:                    }
0774:                } else {
0775:                    TextHitInfo info = layout.hitTestChar(xInSegment,
0776:                            yInSegment, segment.fBounds);
0777:                    result.fOffset = info.getInsertionIndex();
0778:                    if (result.fOffset == 0) {
0779:                        result.fPlacement = TextOffset.AFTER_OFFSET;
0780:                    } else if (result.fOffset == charCount) {
0781:                        result.fPlacement = TextOffset.BEFORE_OFFSET;
0782:                    } else {
0783:                        result.fPlacement = info.isLeadingEdge() ? TextOffset.AFTER_OFFSET
0784:                                : TextOffset.BEFORE_OFFSET;
0785:                    }
0786:                }
0787:
0788:                result.fOffset += segmentCharStart;
0789:                return result;
0790:            }
0791:
0792:            /**
0793:             * Return the offset at the point (x, y).  (x, y) is relative to the top-left
0794:             * of the line.  The leading edge of a right-aligned line is aligned
0795:             * to lineBound.
0796:             */
0797:            private TextOffset pixelToOffset(BidiLayoutInfo line,
0798:                    int lengthBasis, TextOffset result, int lineBound, int x,
0799:                    int y) {
0800:
0801:                if (result == null) {
0802:                    result = new TextOffset();
0803:                }
0804:
0805:                final int yInSegment = y - line.fAscent;
0806:                final int leadingMargin = (line.fLeftToRight) ? line.fLeadingMargin
0807:                        : lineBound - line.fLeadingMargin;
0808:                final int lineCharStart = line.getCharStart(lengthBasis);
0809:
0810:                // first see if point is before leading edge of line
0811:                final int segmentCount = line.fSegments.size();
0812:                {
0813:                    int segLeadingMargin = leadingMargin;
0814:                    if (segmentCount > 0) {
0815:                        BidiSegment firstSeg = (BidiSegment) line.fSegments
0816:                                .elementAt(0);
0817:                        if (line.fLeftToRight) {
0818:                            segLeadingMargin += firstSeg.fDistanceFromLeadingMargin;
0819:                        } else {
0820:                            segLeadingMargin -= firstSeg.fDistanceFromLeadingMargin;
0821:                            segLeadingMargin += (float) firstSeg.fBounds
0822:                                    .getMaxX();
0823:                        }
0824:                    }
0825:                    if (line.fLeftToRight == (x <= segLeadingMargin)) {
0826:                        result.fOffset = lineCharStart;
0827:                        result.fPlacement = TextOffset.AFTER_OFFSET;
0828:                        return result;
0829:                    }
0830:                }
0831:
0832:                int segmentCharStart = lineCharStart;
0833:
0834:                for (int i = 0; i < segmentCount; i++) {
0835:
0836:                    BidiSegment segment = (BidiSegment) line.fSegments
0837:                            .elementAt(i);
0838:                    int segmentOrigin = line.fLeftToRight ? leadingMargin
0839:                            + segment.fDistanceFromLeadingMargin
0840:                            : leadingMargin
0841:                                    - segment.fDistanceFromLeadingMargin;
0842:                    int xInSegment = x - segmentOrigin;
0843:                    if (line.fLeftToRight) {
0844:                        if (segment.fBounds.getMaxX() > xInSegment) {
0845:                            return hitTestSegment(result, segmentCharStart,
0846:                                    segment, xInSegment, yInSegment);
0847:                        }
0848:                    } else {
0849:                        if (segment.fBounds.getX() < xInSegment) {
0850:                            return hitTestSegment(result, segmentCharStart,
0851:                                    segment, xInSegment, yInSegment);
0852:                        }
0853:                    }
0854:                    segmentCharStart += segment.fLayout.getCharacterCount();
0855:                }
0856:
0857:                result.fOffset = lineCharStart + line.fCharLength;
0858:                result.fPlacement = TextOffset.BEFORE_OFFSET;
0859:                return result;
0860:            }
0861:
0862:            private void renderCaret(BidiLayoutInfo line, MConstText text,
0863:                    int lengthBasis, Graphics2D g, int lineBound, int x, int y,
0864:                    final int charOffset, Color strongCaretColor,
0865:                    Color weakCaretColor) {
0866:                final int segmentCount = line.fSegments.size();
0867:                final int lineStart = line.getCharStart(lengthBasis);
0868:
0869:                int currentStart = lineStart;
0870:                BidiSegment segment = null;
0871:                int segmentIndex;
0872:
0873:                for (segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
0874:                    segment = (BidiSegment) line.fSegments
0875:                            .elementAt(segmentIndex);
0876:                    int currentEndpoint = currentStart
0877:                            + segment.fLayout.getCharacterCount();
0878:                    if (currentEndpoint > charOffset) {
0879:                        break;
0880:                    }
0881:                    currentStart = currentEndpoint;
0882:                }
0883:
0884:                /*
0885:                    There are two choices here:
0886:                    1. get carets from a TextLayout and render them, or
0887:                    2. make up a caret ourselves and render it.
0888:                    We want to do 2 when:
0889:                 * there is no text on the line, or
0890:                 * the line ends with a tab and we are drawing the last caret on the line
0891:                    Otherwise, we want 1.
0892:                 */
0893:
0894:                if (segmentIndex == segmentCount && segmentCount > 0) {
0895:                    // If we get here, line length is not 0, and charOffset is at end of line
0896:                    if (!isTab(text.at(charOffset - 1))) {
0897:                        segmentIndex = segmentCount - 1;
0898:                        segment = (BidiSegment) line.fSegments
0899:                                .elementAt(segmentIndex);
0900:                        currentStart = lineStart + line.getCharLength()
0901:                                - segment.fLayout.getCharacterCount();
0902:                    }
0903:                }
0904:
0905:                Object savedPaint = Graphics2DConversion.getColorState(g);
0906:
0907:                try {
0908:                    if (segmentIndex < segmentCount) {
0909:                        TextLayout layout = segment.fLayout;
0910:                        int offsetInLayout = charOffset - currentStart;
0911:                        Shape[] carets = layout.getCaretShapes(offsetInLayout,
0912:                                segment.fBounds);
0913:                        g.setColor(strongCaretColor);
0914:                        int layoutPos = line.fLeadingMargin
0915:                                + segment.fDistanceFromLeadingMargin;
0916:                        int layoutX = line.fLeftToRight ? x + layoutPos : x
0917:                                + lineBound - layoutPos;
0918:                        int layoutY = y + line.fAscent;
0919:
0920:                        // Translating and then clipping doesn't work.  Try this:
0921:                        Rectangle2D.Float clipRect = new Rectangle2D.Float();
0922:                        clipRect.setRect(segment.fBounds);
0923:                        clipRect.x += layoutX;
0924:                        clipRect.y += layoutY;
0925:                        clipRect.width += 1;
0926:                        clipRect.height -= 1;
0927:
0928:                        Object savedClip = ClipWorkaround.saveClipState(g);
0929:                        try {
0930:                            ClipWorkaround.translateAndDrawShapeWithClip(g,
0931:                                    layoutX, layoutY, clipRect, carets[0]);
0932:                            if (carets[1] != null) {
0933:                                g.setColor(weakCaretColor);
0934:                                ClipWorkaround.translateAndDrawShapeWithClip(g,
0935:                                        layoutX, layoutY, clipRect, carets[1]);
0936:                            }
0937:                        } finally {
0938:                            ClipWorkaround.restoreClipState(g, savedClip);
0939:                        }
0940:                    } else {
0941:                        int lineEnd = line.fLeadingMargin + line.fTotalAdvance;
0942:                        int endX = line.fLeftToRight ? lineEnd : lineBound
0943:                                - lineEnd;
0944:                        endX += x;
0945:                        g.drawLine(endX, y, endX, y + line.getHeight() - 1);
0946:                    }
0947:                } finally {
0948:                    Graphics2DConversion.restoreColorState(g, savedPaint);
0949:                }
0950:            }
0951:
0952:            private Rectangle caretBounds(BidiLayoutInfo line, MConstText text,
0953:                    int lengthBasis, int lineBound, int charOffset, int x, int y) {
0954:
0955:                final int segmentCount = line.fSegments.size();
0956:                final int lineStart = line.getCharStart(lengthBasis);
0957:                int currentStart = lineStart;
0958:                BidiSegment segment = null;
0959:                int segmentIndex;
0960:
0961:                for (segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
0962:                    segment = (BidiSegment) line.fSegments
0963:                            .elementAt(segmentIndex);
0964:                    int currentEndpoint = currentStart
0965:                            + segment.fLayout.getCharacterCount();
0966:                    if (currentEndpoint > charOffset) {
0967:                        break;
0968:                    }
0969:                    currentStart = currentEndpoint;
0970:                }
0971:
0972:                if (segmentIndex == segmentCount && segmentCount > 0) {
0973:                    // If we get here, line length is not 0, and charOffset is at end of line
0974:                    if (!isTab(text.at(charOffset - 1))) {
0975:                        segmentIndex = segmentCount - 1;
0976:                        segment = (BidiSegment) line.fSegments
0977:                                .elementAt(segmentIndex);
0978:                        currentStart = lineStart + line.getCharLength()
0979:                                - segment.fLayout.getCharacterCount();
0980:                    }
0981:                }
0982:
0983:                Rectangle r;
0984:
0985:                if (segmentIndex < segmentCount) {
0986:                    TextLayout layout = segment.fLayout;
0987:                    int offsetInLayout = charOffset - currentStart;
0988:                    Shape[] carets = layout.getCaretShapes(offsetInLayout,
0989:                            segment.fBounds);
0990:                    r = carets[0].getBounds();
0991:                    if (carets[1] != null) {
0992:                        r.add(carets[1].getBounds());
0993:                    }
0994:                    r.width += 1;
0995:
0996:                    int layoutPos = line.fLeadingMargin
0997:                            + segment.fDistanceFromLeadingMargin;
0998:                    if (line.fLeftToRight) {
0999:                        r.x += layoutPos;
1000:                    } else {
1001:                        r.x += lineBound - layoutPos;
1002:                    }
1003:                    r.y += line.fAscent;
1004:                } else {
1005:                    r = new Rectangle();
1006:                    r.height = line.getHeight();
1007:                    r.width = 1;
1008:                    int lineEnd = line.fLeadingMargin + line.fTotalAdvance;
1009:                    if (line.fLeftToRight) {
1010:                        r.x = lineEnd;
1011:                    } else {
1012:                        r.x = lineBound - lineEnd;
1013:                    }
1014:                }
1015:
1016:                r.translate(x, y);
1017:                return r;
1018:            }
1019:
1020:            private int strongCaretBaselinePosition(BidiLayoutInfo line,
1021:                    int lengthBasis, int lineBound, int charOffset) {
1022:
1023:                final int segmentCount = line.fSegments.size();
1024:                int currentStart = line.getCharStart(lengthBasis);
1025:                BidiSegment segment = null;
1026:                int segmentIndex;
1027:
1028:                for (segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
1029:                    segment = (BidiSegment) line.fSegments
1030:                            .elementAt(segmentIndex);
1031:                    int currentEndpoint = currentStart
1032:                            + segment.fLayout.getCharacterCount();
1033:                    if (currentEndpoint > charOffset) {
1034:                        break;
1035:                    }
1036:                    currentStart = currentEndpoint;
1037:                }
1038:
1039:                if (segmentIndex < segmentCount) {
1040:                    TextLayout layout = segment.fLayout;
1041:                    int offsetInLayout = charOffset - currentStart;
1042:                    TextHitInfo hit = TextHitInfo.afterOffset(offsetInLayout);
1043:                    hit = TextLayout.DEFAULT_CARET_POLICY.getStrongCaret(hit,
1044:                            hit.getOtherHit(), layout);
1045:                    float[] info = layout.getCaretInfo(hit);
1046:                    int layoutPos = line.fLeadingMargin
1047:                            + segment.fDistanceFromLeadingMargin;
1048:                    if (line.fLeftToRight) {
1049:                        return layoutPos + (int) info[0];
1050:                    } else {
1051:                        return lineBound - layoutPos + (int) info[0];
1052:                    }
1053:                } else {
1054:                    int lineEnd = line.fLeadingMargin + line.fTotalAdvance;
1055:                    if (line.fLeftToRight) {
1056:                        return lineEnd;
1057:                    } else {
1058:                        return lineBound - lineEnd;
1059:                    }
1060:                }
1061:            }
1062:
1063:            private int getNextOffset(BidiLayoutInfo line, int lengthBasis,
1064:                    int charOffset, short dir) {
1065:
1066:                if (dir != MFormatter.eLeft && dir != MFormatter.eRight) {
1067:                    throw new IllegalArgumentException("Invalid direction.");
1068:                }
1069:
1070:                // find segment containing offset:
1071:                final int segmentCount = line.fSegments.size();
1072:                final int lineCharStart = line.getCharStart(lengthBasis);
1073:
1074:                int currentStart = lineCharStart;
1075:                BidiSegment segment = null;
1076:                int segmentIndex;
1077:
1078:                for (segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
1079:                    segment = (BidiSegment) line.fSegments
1080:                            .elementAt(segmentIndex);
1081:                    int currentEndpoint = currentStart
1082:                            + segment.fLayout.getCharacterCount();
1083:                    if (currentEndpoint > charOffset
1084:                            || (segmentIndex == segmentCount - 1 && currentEndpoint == charOffset)) {
1085:                        break;
1086:                    }
1087:                    currentStart = currentEndpoint;
1088:                }
1089:
1090:                final boolean logAdvance = (dir == MFormatter.eRight) == (line.fLeftToRight);
1091:
1092:                int result;
1093:
1094:                if (segmentIndex < segmentCount) {
1095:                    TextLayout layout = segment.fLayout;
1096:                    int offsetInLayout = charOffset - currentStart;
1097:                    TextHitInfo hit = (dir == MFormatter.eLeft) ? layout
1098:                            .getNextLeftHit(offsetInLayout) : layout
1099:                            .getNextRightHit(offsetInLayout);
1100:                    if (hit == null) {
1101:                        result = logAdvance ? currentStart
1102:                                + layout.getCharacterCount() + 1
1103:                                : currentStart - 1;
1104:                    } else {
1105:                        result = hit.getInsertionIndex() + currentStart;
1106:                    }
1107:                } else {
1108:                    result = logAdvance ? lineCharStart + line.fCharLength + 1
1109:                            : lineCharStart - 1;
1110:                }
1111:
1112:                return result;
1113:            }
1114:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.