Source Code Cross Referenced for AsyncFormatter.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:        // Revision: 70 1.38 richtext/AsyncFormatter.java, richtext, richtext
0015:        package com.ibm.richtext.textformat;
0016:
0017:        import java.awt.Graphics;
0018:        import java.awt.Rectangle;
0019:        import java.awt.Point;
0020:        import java.awt.Color;
0021:
0022:        import java.text.BreakIterator;
0023:        import java.text.CharacterIterator;
0024:
0025:        import java.util.Hashtable;
0026:
0027:        import com.ibm.richtext.textlayout.attributes.AttributeMap;
0028:        import com.ibm.richtext.textlayout.attributes.TextAttribute;
0029:
0030:        import com.ibm.richtext.styledtext.MConstText;
0031:
0032:        import com.ibm.richtext.textlayout.Graphics2DConversion;
0033:
0034:        ///*JDK12IMPORTS
0035:        import java.awt.Graphics2D;
0036:        import java.awt.font.LineBreakMeasurer;
0037:        import java.awt.font.FontRenderContext;
0038:
0039:        //JDK12IMPORTS*/
0040:
0041:        /*JDK11IMPORTS
0042:         import com.ibm.richtext.textlayout.Graphics2D;
0043:         import com.ibm.richtext.textlayout.LineBreakMeasurer;
0044:         import com.ibm.richtext.textlayout.FontRenderContext;
0045:         JDK11IMPORTS*/
0046:
0047:        /*
0048:         Change history:
0049:
0050:         7/25/96 -
0051:
0052:         8/15/96
0053:         Fixed bug in textOffsetToPoint (fPixHeight wasn't added to negative heights). {jbr}
0054:
0055:         8/19/96
0056:         Removed references to JustificationStyle constants, and moved them into MFormatter {sfb}
0057:
0058:         8/23/96
0059:         Modified findLineAt and getLineContaining - added optimization in search loop.  Also,
0060:         they were failing when fLTPosEnd+1 == fLTNegStart.  Fixed.
0061:
0062:         8/26/96
0063:         Moved FormatDaemon stuff into this class.
0064:
0065:         9/11/96
0066:         Shortened line returned from textOffsetToPoint by 1 pixel
0067:
0068:         9/23/96
0069:         textOffsetToPoint line length restored (see above).  drawText() now draws only lines
0070:         which fall in rectangle param.
0071:
0072:         9/26/96
0073:         whitespace at end of line is used for caret positioning
0074:
0075:         10/4/96
0076:         Added static TextBox method.
0077:
0078:         10/8/96
0079:         Line 1300 - less than changed to less than or equal in textOffsetToPoint.  Watch for
0080:         hangs in formatText.
0081:
0082:         10/9/96
0083:         Changed sync. model.  fFormatInBackground is used to start/stop bg formatting
0084:
0085:         10/17/96
0086:         Added new flags:  fLineInc, fFillInc for bidi support.  updateFormat, pointToTextOffset, getBoundingRect,
0087:         and findNewInsertionOffset should now function correctly for non-Roman documents.  Nothing else has been
0088:         modified to support intl text.
0089:
0090:         10/21/96
0091:         Pushed paragraph formatting and caret positioning into LineLayout.  In process of pushing
0092:         highlighting into LineLayout.
0093:
0094:         10/24/96
0095:         Now getting paragraph styles from paragraph buffer.
0096:
0097:         7/7/97
0098:         Up-arrow doesn't move to beginning of text if you're on the first line.
0099:
0100:         7/1/98
0101:         No longer intersecting damaged rect with view rect in updateFormat.
0102:         */
0103:
0104:        /**
0105:         * This class implements MFormatter.  It maintains a table of
0106:         * <tt>LayoutInfo</tt> instances which contain layout information
0107:         * for each line in the text.  This class formats lines on demand,
0108:         * and creates a low-priority thread to format text in the background.
0109:         * Note that, at times, some text may not have been formatted, especially
0110:         * if the text is large.
0111:         * <p>
0112:         * The line table is an array of <tt>LayoutInfo</tt> objects, which expands as needed to hold
0113:         * all computed lines in the text.  The line table consists of three
0114:         * regions:  a "positive" region, a "gap," and a "negative" region.
0115:         * In the positive region, character and graphics offsets are positive
0116:         * integers, computed from the beginning of the text / display.  In the
0117:         * gap, line table entries are null.  New lines may be inserted into the gap.
0118:         * In the negative region, character and graphics offsets are negative;
0119:         * their absolute values indicate distances from the end of the text / display.
0120:         * The <tt>fLTPosEnd</tt> member gives the index in the line table of the
0121:         * last positive entry.  The <tt>fLTNegStart</tt> gives the index of first
0122:         * negative entry.  If there are no negative entries, <tt>fLTNegStart</tt> is
0123:         * equal to <tt>fLTSize</tt>, the size of the line table.
0124:         * <p>
0125:         * Changes to the line table occur only in the <tt>formatText()</tt> method.
0126:         * This method calls <tt>LineLayout.layout()</tt> for each line to format.
0127:         *
0128:         * @author John Raley
0129:         *
0130:         * @see MFormatter
0131:         * @see LineLayout
0132:         * @see LayoutContext
0133:         * @see LayoutInfo
0134:         */
0135:
0136:        final class AsyncFormatter extends MFormatter implements  Runnable {
0137:            static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
0138:            /**
0139:             * Text to format.
0140:             */
0141:            private MConstText fText;
0142:
0143:            /**
0144:             * Default values.
0145:             */
0146:            private AttributeMap fDefaultValues;
0147:
0148:            /**
0149:             * Font resolver.
0150:             */
0151:            private FontResolver fFontResolver;
0152:
0153:            /**
0154:             * Default character metric - used to set height of empty paragraphs
0155:             */
0156:            private DefaultCharacterMetric fDefaultCharMetric;
0157:
0158:            /**
0159:             * Length to which lines are formatted.
0160:             */
0161:            private int fLineDim;
0162:
0163:            /**
0164:             * Table of formatted lines.
0165:             */
0166:            private LayoutInfo fLineTable[];
0167:
0168:            /**
0169:             * Size of line table.
0170:             */
0171:            private int fLTSize = 10; // initial size must be > 0
0172:
0173:            /**
0174:             * Index of last positive entry in line table.
0175:             */
0176:            private int fLTPosEnd;
0177:
0178:            /**
0179:             * Index of first negative entry in line table.
0180:             */
0181:            private int fLTNegStart;
0182:
0183:            /**
0184:             * Length of text on which negative line offsets are based.
0185:             * @see #formatText
0186:             */
0187:            private int fLTCurTextLen;
0188:
0189:            /**
0190:             * Length of formatted text in fill direction, in pixels.
0191:             */
0192:            private int fPixHeight;
0193:
0194:            /**
0195:             * Length of formatted text including pseudoline.
0196:             */
0197:            private int fFullPixHeight;
0198:
0199:            private int fMinX;
0200:            private int fMaxX;
0201:
0202:            /**
0203:             * <tt>true</tt> if lines should be formatted to fit line dimension.
0204:             */
0205:            private boolean fWrap;
0206:
0207:            /**
0208:             * <tt>true</tt> if characters run horizontally.
0209:             */
0210:            private boolean fHLine = true;
0211:
0212:            /**
0213:             * <tt>true</tt> if characters run from from low to high coordinates on line.
0214:             */
0215:            private boolean fLineInc = true;
0216:
0217:            /**
0218:             * <tt>true</tt> if lines run from low to high coordinates within page.
0219:             */
0220:            private boolean fFillInc = true;
0221:
0222:            /**
0223:             * Value returned from <tt>findLineAt()</tt>
0224:             * if pixel height precedes topmost line.
0225:             */
0226:            private static final int kBeforeFirstLine = -2;
0227:
0228:            /**
0229:             * Value returned from <tt>findLineAt()</tt> and <tt>getLineContaining()</tt>
0230:             * if offset / pixel height is after all existing lines.
0231:             */
0232:            private static final int kAfterLastLine = -1;
0233:
0234:            /**
0235:             * Thread which invokes formatter in the background.
0236:             */
0237:            private Thread fDaemon;
0238:
0239:            /**
0240:             * FontRenderContext to measure with.  Currently not settable after
0241:             * construction.
0242:             */
0243:            private FontRenderContext fFontRenderContext;
0244:
0245:            /**
0246:             * Controls whether background formatting can run.
0247:             */
0248:            private boolean fBgFormatAllowed = false;
0249:
0250:            /**
0251:             * Cached line break object.
0252:             */
0253:            private BreakIterator fLineBreak = null;
0254:
0255:            /**
0256:             * Cached LineBreakMeasurer.
0257:             */
0258:            private LineBreakMeasurer fCachedMeasurer = null;
0259:            private int fCachedMeasurerStart;
0260:            private int fCachedMeasurerLimit;
0261:
0262:            // Some JDK's (Sun's 1.2.2) throw exceptions from 
0263:            // LineBreakMeasurer.insertChar and deleteChar.  This class
0264:            // detects this condition and doesn't use these two methods
0265:            // if they throw exceptions.
0266:            private static boolean fgCacheMeasurers = true;
0267:
0268:            /**
0269:             * Current text time stamp.  Used to maintain modification invariant.
0270:             */
0271:            private int fCurTimeStamp;
0272:
0273:            /**
0274:             * Cache of ParagraphRenderers.
0275:             */
0276:            private Hashtable fRendererCache = new Hashtable();
0277:
0278:            /**
0279:             * Draw text inside a rectangle. Does not cache any formatting information.
0280:             * This is convenient for small amounts of text; comparable to TETextBox on the Mac.
0281:             * <p>
0282:             * @param text the text to draw
0283:             * @param g Graphics on which to draw
0284:             * @param drawRect rectangle in which text will be drawn
0285:             * @param fillInc if true, lines run from low to high coordinates in page.
0286:             * @param hLine if true, characters run horizontally within a line.
0287:             */
0288:
0289:            private static boolean isParagraphSeparator(char ch) {
0290:
0291:                return ch == '\n' || ch == '\u2029';
0292:            }
0293:
0294:            /**
0295:             * Create an <tt>AsyncFormatter</tt>.
0296:             * @param text the text to format
0297:             * @param lineBound length to which lines are foramtted
0298:             * @param wrap <tt>true</tt> if text should be "line wrapped" (formatted to fit destination area)
0299:             */
0300:            AsyncFormatter(MConstText text, AttributeMap defaultValues,
0301:                    int lineBound, boolean wrap, Graphics g) {
0302:                fText = text;
0303:                fDefaultValues = defaultValues;
0304:                fFontResolver = new FontResolver(fDefaultValues);
0305:
0306:                fLineDim = lineBound;
0307:                fWrap = wrap;
0308:                Graphics2D g2d = Graphics2DConversion.getGraphics2D(g);
0309:                fFontRenderContext = g2d.getFontRenderContext();
0310:
0311:                fDefaultCharMetric = new DefaultCharacterMetric(fFontResolver,
0312:                        fFontRenderContext);
0313:                fLTCurTextLen = text.length();
0314:                removeAllLines();
0315:
0316:                fDaemon = new Thread(this );
0317:                fDaemon.start();
0318:            }
0319:
0320:            public AttributeMap getDefaultValues() {
0321:
0322:                return fDefaultValues;
0323:            }
0324:
0325:            public void checkTimeStamp() {
0326:                String admonition = "Probably, you modified "
0327:                        + "the text before calling stopBackgroundFormatting().";
0328:
0329:                if (fText.getTimeStamp() != fCurTimeStamp) {
0330:                    throw new Error("Time stamp is out of sync.  " + admonition);
0331:                }
0332:                if (fText.length() != fLTCurTextLen) {
0333:                    throw new Error("Length changed unexpectedly.  "
0334:                            + "fText.length()=" + fText.length() + ";  "
0335:                            + "fLTCurTextLen=" + fLTCurTextLen + ";  "
0336:                            + "formatter=" + this  + ";  " + "text=" + fText);
0337:                }
0338:            }
0339:
0340:            /**
0341:             * Specify whether to wrap lines using the line dimension.
0342:             * @param wrap if <tt>true</tt> lines will be wrapped; otherwise new lines will only be
0343:             * started when a newline is encountered.
0344:             */
0345:            public synchronized void setWrap(boolean wrap) {
0346:                if (wrap != fWrap) {
0347:                    fWrap = wrap;
0348:                    removeAllLines();
0349:                }
0350:            }
0351:
0352:            /**
0353:             * Return true if lines are wrapped using the line dimension.
0354:             * @see #setWrap
0355:             */
0356:            public synchronized boolean wrap() {
0357:                return fWrap;
0358:            }
0359:
0360:            /**
0361:             * Specify the lineBound in pixels.  If line wrapping is on, lines
0362:             * will be wrapped to this value.
0363:             * <p>
0364:             *
0365:             * @param lineBound the distance, in pixels, used to wrap lines.
0366:             */
0367:            public synchronized void setLineBound(int lineBound) {
0368:                if (fLineDim != lineBound) {
0369:                    fLineDim = lineBound;
0370:                    if (fWrap) {
0371:                        removeAllLines();
0372:                    }
0373:                }
0374:            }
0375:
0376:            /**
0377:             * Return the number of pixels along the line dimension.
0378:             */
0379:            public synchronized int lineBound() {
0380:                return fLineDim;
0381:            }
0382:
0383:            /**
0384:             * Return <tt>true</tt> if characters run from low to high coordinates on line.
0385:             */
0386:            private boolean lineInc() {
0387:                return fLineInc;
0388:            }
0389:
0390:            /**
0391:             * Return <tt>true</tt> if lines run from low to high coordinates on page.
0392:             */
0393:            private boolean fillInc() {
0394:                return fFillInc;
0395:            }
0396:
0397:            /**
0398:             * Remove all lines in the line table.  Used after an operation that
0399:             * invalidates all existing lines, such as changing line wrapping or the
0400:             * line dim.
0401:             */
0402:            private synchronized void removeAllLines() {
0403:                fCurTimeStamp = fText.getTimeStamp();
0404:                stopBackgroundFormatting();
0405:
0406:                fMinX = 0;
0407:                fMaxX = fLineDim;
0408:
0409:                fLineTable = new LayoutInfo[fLTSize]; // fLTSize must be > 0
0410:                fLTNegStart = fLTSize;
0411:                fLTPosEnd = 0;
0412:
0413:                fLineTable[0] = pseudoLineInfo(null, 0);
0414:
0415:                fPixHeight = fLineTable[0].getHeight(); // ??? or should it be zero?
0416:                fFullPixHeight = fPixHeight;
0417:
0418:                // format at least one line:
0419:                formatToHeight(fPixHeight + 1);
0420:
0421:                enableBGFormat();
0422:            }
0423:
0424:            /**
0425:             * Fill the layout info with information appropriate to the pseudoline.
0426:             */
0427:            private synchronized LayoutInfo pseudoLineInfo(LayoutInfo info,
0428:                    int offset) {
0429:                AttributeMap st = fText.paragraphStyleAt(fLTCurTextLen); // ??? if text is empty or this is the end of the text, what happens?
0430:                ParagraphRenderer renderer = getRendererFor(st);
0431:                info = renderer.layout(fText, info, (LineBreakMeasurer) null,
0432:                        fFontRenderContext, offset, offset, fLineDim, fLineDim);
0433:
0434:                return info;
0435:            }
0436:
0437:            /**
0438:             * Return the index of the last valid line in the line table.
0439:             */
0440:            private int lastLine() {
0441:                return (fLTNegStart == fLTSize) ? fLTPosEnd : fLTSize - 1;
0442:            }
0443:
0444:            /**
0445:             * Shift line table such that <tt>lastPos</tt> is the last positive
0446:             * entry in the table. <b>NOTE: <tt>lastPos</tt> must be a valid line!</b>
0447:             * <p>
0448:             * @param lastPos the index of the line which will become the last positive
0449:             * entry in the line table
0450:             */
0451:            private void shiftTableTo(int lastPos) {
0452:                LayoutInfo li;
0453:
0454:                while (lastPos < fLTPosEnd) { // shift +'s to -'s
0455:                    li = fLineTable[fLTPosEnd];
0456:                    fLineTable[fLTPosEnd--] = null;
0457:
0458:                    li.makeRelativeToEnd(fLTCurTextLen, fPixHeight);
0459:
0460:                    fLineTable[--fLTNegStart] = li;
0461:                }
0462:
0463:                while (lastPos >= fLTNegStart) { // shift -'s to +'s
0464:                    li = fLineTable[fLTNegStart];
0465:                    fLineTable[fLTNegStart++] = null;
0466:
0467:                    li.makeRelativeToBeginning(fLTCurTextLen, fPixHeight);
0468:
0469:                    fLineTable[++fLTPosEnd] = li;
0470:                }
0471:            }
0472:
0473:            /**
0474:             * Increase the size of the line table.
0475:             */
0476:            private void expandLineTable() {
0477:                // This just doubles the size of the line table.
0478:
0479:                LayoutInfo newLineTable[] = new LayoutInfo[fLineTable.length * 2];
0480:                int newNegStart = newLineTable.length
0481:                        - (fLineTable.length - fLTNegStart);
0482:
0483:                System.arraycopy(fLineTable, 0, newLineTable, 0, fLTPosEnd + 1);
0484:                System.arraycopy(fLineTable, fLTNegStart, newLineTable,
0485:                        newNegStart, fLTSize - fLTNegStart);
0486:
0487:                fLTNegStart = newNegStart;
0488:                fLTSize = newLineTable.length;
0489:                fLineTable = newLineTable;
0490:            }
0491:
0492:            /**
0493:             * Return the index of the line containing the pixel position <tt>fillCoord</tt>.
0494:             * If fillCoord exceeds the bottom of the text, return kAfterLastLine.
0495:             * If fillCoord is less than the top of the text, return kBeforeFirstLine.
0496:             * <p>
0497:             * @param fillCoord "height" of line to locate.
0498:             */
0499:            private int findLineAt(int fillCoord) {
0500:                int low, high, mid;
0501:                int lowStart, highStart, midStart;
0502:
0503:                if (fillCoord >= fPixHeight)
0504:                    return kAfterLastLine;
0505:                else if (fillCoord < 0)
0506:                    return kBeforeFirstLine;
0507:
0508:                if ((fLTNegStart < fLTSize)
0509:                        && (fillCoord >= fLineTable[fLTNegStart]
0510:                                .getGraphicStart(fPixHeight))) {
0511:                    fillCoord -= fPixHeight;
0512:
0513:                    low = fLTNegStart;
0514:                    high = fLTSize;
0515:                    highStart = 0;
0516:                } else {
0517:                    low = 0;
0518:                    high = fLTPosEnd + 1;
0519:                    highStart = fLineTable[fLTPosEnd].getGraphicStart(0)
0520:                            + fLineTable[fLTPosEnd].getHeight();
0521:                }
0522:                lowStart = fLineTable[low].getGraphicStart(0);
0523:
0524:                do {
0525:                    if (lowStart == highStart)
0526:                        return low;
0527:
0528:                    mid = low + (fillCoord - lowStart) / (highStart - lowStart)
0529:                            * (high - low);
0530:                    midStart = fLineTable[mid].getGraphicStart(0);
0531:
0532:                    if (midStart > fillCoord) {
0533:                        high = mid;
0534:                        highStart = fLineTable[high].getGraphicStart(0);
0535:                    } else if (midStart + fLineTable[mid].getHeight() <= fillCoord) {
0536:                        low = mid + 1;
0537:                        lowStart = fLineTable[low].getGraphicStart(0);
0538:                    } else
0539:                        return mid;
0540:
0541:                } while (low < high);
0542:
0543:                return 0;
0544:            }
0545:
0546:            /**
0547:             * Return the index of the first character in the line.
0548:             * @param line the internal index of the line (direct index into linetable).
0549:             */
0550:            private int lineCharStartInternal(int line) {
0551:                return fLineTable[line].getCharStart(fLTCurTextLen);
0552:            }
0553:
0554:            /**
0555:             * Return the index of the character following the last character in the line.
0556:             * @param line the internal index of the line (direct index into linetable).
0557:             */
0558:            private int lineCharLimitInternal(int line) {
0559:                return lineCharStartInternal(line)
0560:                        + fLineTable[line].getCharLength();
0561:            }
0562:
0563:            /**
0564:             * Return the graphic start of the line, unadjusted for fill direction.
0565:             * @param line the internal index of the line (direct index into linetable).
0566:             */
0567:            private int lineGraphicStartInternal(int line) {
0568:                return fLineTable[line].getGraphicStart(fPixHeight);
0569:            }
0570:
0571:            /**
0572:             * Return the graphic limit of the line, unadjusted for fill direction.
0573:             * @param line the internal index of the line (direct index into linetable).
0574:             */
0575:            private int lineGraphicLimitInternal(int line) {
0576:                return lineGraphicStartInternal(line)
0577:                        + fLineTable[line].getHeight();
0578:            }
0579:
0580:            /**
0581:             * Return the offset of the first character which has not been formatted.
0582:             * If all text has been formatted, return the current text length.
0583:             */
0584:            private int lastLineCharStop() {
0585:                return lineCharLimitInternal(lastLine());
0586:            }
0587:
0588:            /**
0589:             * Return a 'valid' line containing offset.  This differs from getLineContaining in
0590:             * this maps kAfterLastLine to lastLine(), so that the result is always a valid
0591:             * linetable index.
0592:             */
0593:            private int getValidLineContaining(TextOffset offset) {
0594:
0595:                return getValidLineContaining(offset.fOffset, offset.fPlacement);
0596:            }
0597:
0598:            /**
0599:             * Return a 'valid' line containing offset.  This differs from getLineContaining in
0600:             * this maps kAfterLastLine to lastLine(), so that the result is always a valid
0601:             * linetable index.
0602:             */
0603:            private int getValidLineContaining(int insOffset, boolean placement) {
0604:                int line = getLineContaining(insOffset, placement);
0605:                if (line == kAfterLastLine)
0606:                    line = lastLine();
0607:                else if (line == kBeforeFirstLine)
0608:                    throw new IllegalArgumentException(
0609:                            "Debug: getLineContaining returned kBeforeFirstLine");
0610:
0611:                return line;
0612:            }
0613:
0614:            /**
0615:             * Return index of line containing <tt>offset</tt>.
0616:             * ??? If offset is after last formatted line, returns kAfterLastLine.  Is that good?
0617:             * <p>
0618:             * @param offset the offset whose line should be located
0619:             * @returns line containing <tt>offset</tt>
0620:             */
0621:            private int getLineContaining(TextOffset offset) {
0622:
0623:                return getLineContaining(offset.fOffset, offset.fPlacement);
0624:            }
0625:
0626:            private int getLineContaining(int insOffset, boolean placement) {
0627:                int pos = insOffset;
0628:                if (placement == TextOffset.BEFORE_OFFSET && pos > 0)
0629:                    --pos;
0630:
0631:                if (pos < 0) {
0632:                    throw new IllegalArgumentException(
0633:                            "Debug: getLineContaining offset < 0: " + pos);
0634:                }
0635:
0636:                if (pos >= lastLineCharStop()) {
0637:                    return emptyParagraphAtEndOfText() ? kAfterLastLine
0638:                            : lastLine();
0639:                }
0640:
0641:                int low, high, mid;
0642:                int lowStart, highStart, midStart;
0643:
0644:                if ((fLTNegStart < fLTSize)
0645:                        && (pos >= fLineTable[fLTNegStart]
0646:                                .getCharStart(fLTCurTextLen))) {
0647:                    pos -= fLTCurTextLen;
0648:
0649:                    low = fLTNegStart;
0650:                    high = fLTSize;
0651:                    highStart = 0;
0652:                } else {
0653:                    low = 0;
0654:                    high = fLTPosEnd + 1;
0655:                    highStart = fLineTable[fLTPosEnd].getCharStart(0)
0656:                            + fLineTable[fLTPosEnd].getCharLength();
0657:                }
0658:                lowStart = fLineTable[low].getCharStart(0);
0659:
0660:                do {
0661:                    if (highStart == lowStart) {
0662:                        return low;
0663:                    }
0664:
0665:                    mid = low + (pos - lowStart) / (highStart - lowStart)
0666:                            * (high - low);
0667:                    midStart = fLineTable[mid].getCharStart(0);
0668:
0669:                    if (midStart > pos) {
0670:                        high = mid;
0671:                        highStart = fLineTable[high].getCharStart(0);
0672:                    } else if (midStart + fLineTable[mid].getCharLength() <= pos) {
0673:                        low = mid + 1;
0674:                        lowStart = fLineTable[low].getCharStart(0);
0675:                    } else {
0676:                        return mid;
0677:                    }
0678:
0679:                } while (low < high);
0680:
0681:                return 0;
0682:            }
0683:
0684:            /**
0685:             * Display text in drawArea. Does not reformat text.
0686:             * <p>
0687:             * @param g the Graphics object in which to draw
0688:             * @param drawArea the rectangle, in g's coordinate system, in which to draw
0689:             * @param origin the top-left corner of the text, in g's coordinate system
0690:             */
0691:            public synchronized void draw(Graphics g, Rectangle drawArea,
0692:                    Point origin) {
0693:                draw(g, drawArea, origin, null, null, null);
0694:            }
0695:
0696:            public synchronized void draw(Graphics g, Rectangle drawArea,
0697:                    Point origin, TextOffset selStart, TextOffset selStop,
0698:                    Color highlight) {
0699:
0700:                checkTimeStamp();
0701:                Graphics2D g2d = Graphics2DConversion.getGraphics2D(g);
0702:
0703:                // Get starting and ending fill 'heights.'
0704:
0705:                int startFill;
0706:                int endFill;
0707:
0708:                if (fFillInc)
0709:                    startFill = drawArea.y - origin.y;
0710:                else
0711:                    startFill = origin.y - (drawArea.y + drawArea.height);
0712:
0713:                endFill = startFill + drawArea.height;
0714:
0715:                // We're drawing one more line than necessary when we update because of a
0716:                // selection change.  But we're drawing the right amount of lines when we
0717:                // refresh the whole display.  This affects rendering speed significantly,
0718:                // and creating a new paragraph renderer for each line doesn't help either.
0719:                // For now, I'm going to subtract one from the fill height, on the theory
0720:                // that we're picking up the extra line because of a one-pixel slop.
0721:                // This seems to work, although perhaps if one pixel of a line at the
0722:                // bottom should draw, it won't.
0723:
0724:                --endFill;
0725:
0726:                // Format to ending fill height, so line table is valid for all lines we need to draw.
0727:
0728:                formatToHeight(endFill);
0729:
0730:                // Get starting and ending lines for fill height.  If the start of the fill is after the last line,
0731:                // or the end of the fill is before the first line, return.
0732:
0733:                int curLine = findLineAt(startFill);
0734:                if (curLine == kAfterLastLine)
0735:                    return;
0736:                else if (curLine == kBeforeFirstLine)
0737:                    curLine = 0;
0738:
0739:                int lastLine = findLineAt(endFill);
0740:                if (lastLine == kBeforeFirstLine)
0741:                    return;
0742:                else if (lastLine == kAfterLastLine)
0743:                    lastLine = lastLine();
0744:
0745:                // Get the base coordinates (lineX, lineY) for the starting line.
0746:
0747:                int lineX, lineY;
0748:
0749:                int gStart = lineGraphicStartInternal(curLine);
0750:
0751:                if (fHLine) {
0752:                    if (fLineInc)
0753:                        lineX = origin.x;
0754:                    else
0755:                        lineX = origin.x - fLineDim;
0756:                    if (fFillInc)
0757:                        lineY = origin.y + gStart;
0758:                    else
0759:                        lineY = origin.y
0760:                                - (gStart + fLineTable[curLine].getHeight());
0761:                } else {
0762:                    if (fLineInc)
0763:                        lineY = origin.y;
0764:                    else
0765:                        lineY = origin.y - fLineDim;
0766:                    if (fFillInc)
0767:                        lineX = origin.x + gStart;
0768:                    else
0769:                        lineX = origin.x
0770:                                - (gStart + fLineTable[curLine].getHeight());
0771:                }
0772:
0773:                // Iterate through lines, drawing each one and incrementing the base coordinate by the line height.
0774:
0775:                for (; curLine <= lastLine; curLine++) {
0776:                    // Adjust curLine around gap in line table.
0777:                    if ((curLine > fLTPosEnd) && (curLine < fLTNegStart))
0778:                        curLine = fLTNegStart;
0779:
0780:                    fLineTable[curLine].renderWithHighlight(fLTCurTextLen, g2d,
0781:                            fLineDim, lineX, lineY, selStart, selStop,
0782:                            highlight);
0783:
0784:                    // Increment line base for next iteration.
0785:                    int lineInc = fLineTable[curLine].getHeight();
0786:                    if (fFillInc) {
0787:                        if (fHLine)
0788:                            lineY += lineInc;
0789:                        else
0790:                            lineX += lineInc;
0791:                    } else {
0792:                        if (fHLine)
0793:                            lineY -= lineInc;
0794:                        else
0795:                            lineX -= lineInc;
0796:                    }
0797:                }
0798:            }
0799:
0800:            /**
0801:             * Format text to given height.
0802:             * @param height the height to which text will be formatted.
0803:             */
0804:            public synchronized void formatToHeight(int reqHeight) {
0805:                checkTimeStamp();
0806:                if (reqHeight <= fPixHeight) // already formatted to this height
0807:                    return;
0808:
0809:                if (fText.length() == lastLineCharStop()) // already formatted all the text
0810:                    return;
0811:
0812:                // +++ should disable update thread here
0813:
0814:                if (fLTNegStart < fLTSize)
0815:                    shiftTableTo(fLTSize - 1);
0816:
0817:                formatText(0, 0, reqHeight, false);
0818:            }
0819:
0820:            /**
0821:             * Format text to given offset.
0822:             * @param offset the offset to which text will be formatted.
0823:             */
0824:            private void formatToOffset(TextOffset offset) {
0825:                formatToOffset(offset.fOffset, offset.fPlacement);
0826:            }
0827:
0828:            private synchronized void formatToOffset(int offset,
0829:                    boolean placement) {
0830:
0831:                checkTimeStamp();
0832:                int llcs = lastLineCharStop();
0833:                if (llcs < fLTCurTextLen) {
0834:                    int limit = offset;
0835:                    if (placement == TextOffset.AFTER_OFFSET) // format to past character offset is associated with
0836:                        limit++;
0837:                    if (limit >= llcs) { // ??? would '>' be ok instead or '>='?
0838:                        if (limit > fLTCurTextLen)
0839:                            limit = fLTCurTextLen;
0840:
0841:                        shiftTableTo(lastLine());
0842:                        formatText(llcs, limit - llcs, Integer.MAX_VALUE, true);
0843:                    }
0844:                }
0845:            }
0846:
0847:            /**
0848:             * Reformat text after a change.
0849:             * After the formatter's text changes, call this method to reformat.  Does
0850:             * not redraw.
0851:             * @param afStart the offset into the text where modification began;  ie, the
0852:             * first character in the text which is "different" in some way.  Does not
0853:             * have to be nonnegative.
0854:             * @param afLength the number of new or changed characters in the text.  Should never
0855:             * be less than 0.
0856:             * @param viewRect the Rectangle in which the text will be displayed.  This is needed for
0857:             * returning the "damaged" area - the area of the screen in which the text must be redrawn.
0858:             * @param origin the top-left corner of the text, in the display's coordinate system
0859:             * @returns a <tt>Rectangle</tt> which specifies the area in which text must be
0860:             * redrawn to reflect the change to the text.
0861:             */
0862:            public Rectangle updateFormat(final int afStart,
0863:                    final int afLength, Rectangle viewRect, Point origin) {
0864:                if (afStart < 0) {
0865:                    throw new IllegalArgumentException(
0866:                            "Debug: updateFormat afStart < 0: " + afStart);
0867:                }
0868:                if (fBgFormatAllowed) {
0869:                    throw new IllegalArgumentException(
0870:                            "Background formatting should have been disabled");
0871:                }
0872:                fCurTimeStamp = fText.getTimeStamp();
0873:
0874:                int curLine = getValidLineContaining(afStart,
0875:                        TextOffset.AFTER_OFFSET);
0876:                int lineStartPos = lineCharStartInternal(curLine);
0877:
0878:                // optimize by finding out whether change occurred
0879:                // after first word break on curline
0880:
0881:                int firstPossibleBreak;
0882:
0883:                if (lineStartPos < fText.length()) {
0884:
0885:                    if (fLineBreak == null) {
0886:                        fLineBreak = BreakIterator.getLineInstance();
0887:                    }
0888:                    CharacterIterator charIter = fText
0889:                            .createCharacterIterator();
0890:                    charIter.setIndex(lineStartPos);
0891:                    fLineBreak.setText(charIter);
0892:
0893:                    firstPossibleBreak = fLineBreak.following(lineStartPos);
0894:                } else
0895:                    firstPossibleBreak = afStart;
0896:
0897:                if ((curLine > 0)
0898:                        && (firstPossibleBreak == BreakIterator.DONE || afStart <= firstPossibleBreak)) {
0899:                    curLine--;
0900:                    if (curLine < fLTNegStart && curLine > fLTPosEnd)
0901:                        curLine = fLTPosEnd;
0902:                }
0903:
0904:                shiftTableTo(curLine);
0905:
0906:                int pixHeight; // after the formatText call, at least pixHeight text must be formatted
0907:
0908:                if (fHLine) {
0909:                    if (fFillInc)
0910:                        pixHeight = viewRect.y + viewRect.height - origin.y;
0911:                    else
0912:                        pixHeight = origin.y - viewRect.y;
0913:                } else {
0914:                    if (fFillInc)
0915:                        pixHeight = viewRect.x + viewRect.width - origin.x;
0916:                    else
0917:                        pixHeight = origin.x - viewRect.x;
0918:                }
0919:
0920:                Rectangle r = formatText(afStart, afLength, pixHeight, false);
0921:
0922:                //dumpLineTable();
0923:
0924:                if ((fPixHeight < pixHeight) && (fLTNegStart < fLTSize)
0925:                        && (fLTCurTextLen > lastLineCharStop())) {
0926:                    shiftTableTo(lastLine());
0927:                    Rectangle s = formatText(0, 0, pixHeight, false);
0928:                    r = r.union(s);
0929:                }
0930:
0931:                intlRect(origin, r);
0932:                //System.out.println("Damaged rect: "+r+"; origin: "+origin);
0933:
0934:                // don't need to synchronized here, b/c the daemon shouldn't be running when
0935:                // this is executing
0936:
0937:                if (fText.length() < lastLineCharStop())
0938:                    enableBGFormat();
0939:                else
0940:                    stopBackgroundFormatting();
0941:
0942:                //dumpLineTable();
0943:
0944:                return r;
0945:            }
0946:
0947:            private LineBreakMeasurer makeMeasurer(int paragraphStart,
0948:                    int paragraphLimit) {
0949:
0950:                MTextIterator iter = new MTextIterator(fText, fFontResolver,
0951:                        paragraphStart, paragraphLimit);
0952:                LineBreakMeasurer measurer = new LineBreakMeasurer(iter,
0953:                        fFontRenderContext);
0954:                if (fgCacheMeasurers) {
0955:                    fCachedMeasurerStart = paragraphStart;
0956:                    fCachedMeasurerLimit = paragraphLimit;
0957:                    fCachedMeasurer = measurer;
0958:                }
0959:                return measurer;
0960:            }
0961:
0962:            /**
0963:             * Compute text format.  This method calculates text format;  it can be
0964:             * called for various purposes:  to reformat text after an edit, to
0965:             * format text to a particular height, or to format text up to a
0966:             * particular offset.
0967:             * <p>
0968:             * The calling method must ensure that <tt>fLineTable</tt> has been shifted
0969:             * such that the last positive line is where the formatting operation will
0970:             * begin.
0971:             * <p>
0972:             * Called by: <tt>formatToHeight()</tt>, <tt>updateFormat()</tt>,
0973:             * <tt>textOffsetToPoint()</tt>, <tt>getBoundingRect()</tt>
0974:             * @param afStart the offset of the first character in the text which has changed
0975:             * @param afLength the number of new or changed characters in the text
0976:             * @param reqHeight the pixel height to which text must be formatted.  Ignored
0977:             * if <tt>formatAllNewText</tt> is <tt>true</tt>, or if old lines remain in the
0978:             * line table after all changed text has been formatted.
0979:             * @param seekOffsetAtEnd if <tt>true</tt>, formatting continues until the line
0980:             * containing afStart+afLength has been formatted.  If false, formatting may stop
0981:             * when reqHeight has been reached.  This parameter should be <tt>true</tt> <b>only</b>
0982:             * if the object of the formatting operation is to extend formatting to a particular
0983:             * offset within the text;  it should be <tt>false</tt> everywhere else.
0984:             * @returns a rectangle, relative to the top-left of the text, which encloses the
0985:             * screen area whose appearance has changed due to the reformatting.
0986:             */
0987:
0988:            private Rectangle formatText(int afStart, final int afLength,
0989:                    int reqHeight, boolean seekOffsetAtEnd) {
0990:                /* assumes line table shifted such that first line to format is
0991:                last positive line */
0992:
0993:                if (afLength < 0) {
0994:                    throw new IllegalArgumentException(
0995:                            "afLength < 0.  afLength=" + afLength);
0996:                }
0997:
0998:                int newTextEnd = afStart + afLength;
0999:
1000:                final int newCurTextLen = fText.length();
1001:
1002:                // variable not used int oldPixHeight = fPixHeight;
1003:                int oldFullPixHeight = fFullPixHeight;
1004:                fPixHeight -= fLineTable[fLTPosEnd].getHeight();
1005:
1006:                int curGraphicStart = fLineTable[fLTPosEnd]
1007:                        .getGraphicStart(fPixHeight);
1008:                int curLineStart = fLineTable[fLTPosEnd]
1009:                        .getCharStart(newCurTextLen);
1010:
1011:                int curParagraphStart = fText.paragraphStart(curLineStart);
1012:                int curParagraphLimit = Integer.MIN_VALUE; // dummy value
1013:
1014:                int damageStart = curGraphicStart;
1015:
1016:                ParagraphRenderer renderer = null;
1017:                LineBreakMeasurer measurer = null;
1018:
1019:                // try to use cached LineBreakMeasurer if possible
1020:                if (fCachedMeasurer != null
1021:                        && curParagraphStart == fCachedMeasurerStart) {
1022:
1023:                    curParagraphLimit = fText.paragraphLimit(curParagraphStart);
1024:
1025:                    try {
1026:                        if (newCurTextLen - fLTCurTextLen == 1 && afLength == 1) {
1027:                            if (curParagraphLimit == fCachedMeasurerLimit + 1) {
1028:                                MTextIterator iter = new MTextIterator(fText,
1029:                                        fFontResolver, curParagraphStart,
1030:                                        curParagraphLimit);
1031:                                fCachedMeasurer.insertChar(iter, afStart);
1032:                                fCachedMeasurerLimit += 1;
1033:                                measurer = fCachedMeasurer;
1034:                            }
1035:                        } else if (fLTCurTextLen - newCurTextLen == 1
1036:                                && afLength == 0) {
1037:                            if (fCachedMeasurerLimit > fCachedMeasurerStart + 1
1038:                                    && curParagraphLimit == fCachedMeasurerLimit - 1) {
1039:                                MTextIterator iter = new MTextIterator(fText,
1040:                                        fFontResolver, curParagraphStart,
1041:                                        curParagraphLimit);
1042:                                fCachedMeasurer.deleteChar(iter, afStart);
1043:                                fCachedMeasurerLimit -= 1;
1044:                                measurer = fCachedMeasurer;
1045:                            }
1046:                        }
1047:                    } catch (ArrayIndexOutOfBoundsException e) {
1048:                        fCachedMeasurer = null;
1049:                        fgCacheMeasurers = false;
1050:                    }
1051:
1052:                    if (measurer != null) {
1053:                        // need to set up renderer since the paragraph update in the
1054:                        // formatting loop will not happen
1055:                        AttributeMap style = fText
1056:                                .paragraphStyleAt(curParagraphStart);
1057:                        renderer = getRendererFor(style);
1058:                        measurer.setPosition(curLineStart);
1059:                    }
1060:                }
1061:
1062:                if (measurer == null) {
1063:                    // trigger paragraph update at start of formatting loop
1064:                    curParagraphLimit = curParagraphStart;
1065:                    curParagraphStart = 0;
1066:                }
1067:
1068:                fLTCurTextLen = newCurTextLen;
1069:
1070:                while (true) {
1071:                    // System.out.println("line: " + fLTPosEnd + ", cls: " + curLineStart);
1072:
1073:                    if (curLineStart >= curParagraphLimit) {
1074:                        curParagraphStart = curParagraphLimit;
1075:                        curParagraphLimit = fText
1076:                                .paragraphLimit(curParagraphStart);
1077:
1078:                        AttributeMap style = fText
1079:                                .paragraphStyleAt(curParagraphStart);
1080:                        renderer = getRendererFor(style);
1081:
1082:                        if (curParagraphStart < curParagraphLimit) {
1083:                            measurer = makeMeasurer(curParagraphStart,
1084:                                    curParagraphLimit);
1085:                            measurer.setPosition(curLineStart);
1086:                        } else {
1087:                            measurer = null;
1088:                        }
1089:                    }
1090:
1091:                    {
1092:                        boolean haveOldDirection = fLineTable[fLTPosEnd] != null;
1093:                        boolean oldDirection = false; //  dummy value for compiler
1094:                        if (haveOldDirection) {
1095:                            oldDirection = fLineTable[fLTPosEnd]
1096:                                    .isLeftToRight();
1097:                        }
1098:
1099:                        fLineTable[fLTPosEnd] = renderer.layout(fText,
1100:                                fLineTable[fLTPosEnd], measurer,
1101:                                fFontRenderContext, curParagraphStart,
1102:                                curParagraphLimit, fWrap ? fLineDim
1103:                                        : Integer.MAX_VALUE, fLineDim);
1104:                        if (haveOldDirection) {
1105:                            if (fLineTable[fLTPosEnd].isLeftToRight() != oldDirection) {
1106:                                newTextEnd = Math.max(newTextEnd,
1107:                                        curParagraphLimit);
1108:                            }
1109:                        }
1110:                    }
1111:
1112:                    {
1113:                        LayoutInfo theLine = fLineTable[fLTPosEnd];
1114:
1115:                        theLine.setGraphicStart(curGraphicStart);
1116:                        curGraphicStart += theLine.getHeight();
1117:
1118:                        fPixHeight += theLine.getHeight();
1119:                        curLineStart += theLine.getCharLength();
1120:
1121:                        if (!fWrap) {
1122:                            int lineWidth = theLine.getTotalAdvance()
1123:                                    + theLine.getLeadingMargin();
1124:                            if (theLine.isLeftToRight()) {
1125:                                if (fMaxX < lineWidth) {
1126:                                    fMaxX = lineWidth;
1127:                                }
1128:                            } else {
1129:                                if (fLineDim - lineWidth < fMinX) {
1130:                                    fMinX = fLineDim - lineWidth;
1131:                                }
1132:                            }
1133:                        }
1134:                    }
1135:                    /*
1136:                        Next, discard obsolete lines.  A line is obsolete if it
1137:                        contains new text or text which has been formatted.
1138:                     */
1139:
1140:                    while (fLTNegStart < fLTSize) {
1141:                        int linePos = fLineTable[fLTNegStart]
1142:                                .getCharStart(newCurTextLen);
1143:                        if (linePos >= curLineStart && linePos >= newTextEnd)
1144:                            break;
1145:
1146:                        // System.out.println("delete neg line: " + fLTNegStart);
1147:                        fPixHeight -= fLineTable[fLTNegStart].getHeight();
1148:                        fLineTable[fLTNegStart++] = null;
1149:                    }
1150:
1151:                    int stopAt;
1152:                    if (fLTNegStart < fLTSize)
1153:                        stopAt = fLineTable[fLTNegStart]
1154:                                .getCharStart(newCurTextLen);
1155:                    else
1156:                        stopAt = newCurTextLen;
1157:
1158:                    /*
1159:                        Now, if exit conditions aren't met, create a new line.
1160:                     */
1161:
1162:                    if (seekOffsetAtEnd) {
1163:                        if ((curLineStart >= newTextEnd)
1164:                                && (fLTNegStart == fLTSize)) {
1165:                            // System.out.println("break 1");
1166:                            break;
1167:                        }
1168:                    } else {
1169:                        if (curLineStart >= stopAt) {
1170:                            // System.out.println("curLineStart: " + curLineStart + " >= stopAt: " + stopAt);
1171:                            break;
1172:                        } else if (fLTNegStart == fLTSize
1173:                                && fPixHeight >= reqHeight) {
1174:                            // System.out.println("break 3");
1175:                            break;
1176:                        }
1177:                    }
1178:
1179:                    if (fLTPosEnd + 1 == fLTNegStart)
1180:                        expandLineTable();
1181:
1182:                    fLineTable[++fLTPosEnd] = null; // will be created by Renderer
1183:                }
1184:                //System.out.print("\n");
1185:
1186:                if (newCurTextLen == 0) {
1187:                    fLineTable[0] = pseudoLineInfo(fLineTable[0], 0);
1188:                    fPixHeight = fLineTable[0].getHeight();
1189:                }
1190:                fFullPixHeight = fPixHeight;
1191:
1192:                if (isParaBreakBefore(newCurTextLen)) {
1193:                    fFullPixHeight += lastCharHeight();
1194:                }
1195:                /*
1196:                 System.out.println("curLineStart: " + curLineStart +
1197:                 ", fLTPosEnd: " + fLTPosEnd +
1198:                 ", fLTNegStart: " + fLTNegStart +
1199:                 ", fLTSize: " + fLTSize);
1200:
1201:                 System.out.println("oldFullPixHeight: " + oldFullPixHeight + ", newFullPixHeight: " + fFullPixHeight);
1202:                 */
1203:                int damageLength;
1204:                if (fFullPixHeight == oldFullPixHeight) {
1205:                    damageLength = fLineTable[fLTPosEnd]
1206:                            .getGraphicStart(fPixHeight)
1207:                            + fLineTable[fLTPosEnd].getHeight() - damageStart;
1208:                } else {
1209:                    damageLength = Math.max(fFullPixHeight, oldFullPixHeight);
1210:                }
1211:
1212:                return new Rectangle(fMinX, damageStart, fMaxX - fMinX,
1213:                        damageLength);
1214:            }
1215:
1216:            private void dumpLineTable() {
1217:                int i;
1218:
1219:                System.out.println("fLTCurTextLen=" + fLTCurTextLen + " ");
1220:                for (i = 0; i <= fLTPosEnd; i++)
1221:                    System.out.println("Line " + i + " starts at "
1222:                            + fLineTable[i].getCharStart(fLTCurTextLen)
1223:                            + " and extends " + fLineTable[i].getCharLength());
1224:
1225:                for (i = fLTNegStart; i < fLTSize; i++)
1226:                    System.out.println("Line "
1227:                            + (i - fLTNegStart + fLTPosEnd + 1) + " starts at "
1228:                            + fLineTable[i].getCharStart(fLTCurTextLen)
1229:                            + " and extends " + fLineTable[i].getCharLength());
1230:            }
1231:
1232:            public synchronized int minX() {
1233:
1234:                return fMinX;
1235:            }
1236:
1237:            /**
1238:             * Return the horizontal extent of the text, in pixels.
1239:             * <p>
1240:             * This returns an approximation based on the currently formatted text.
1241:             */
1242:            public synchronized int maxX() {
1243:                checkTimeStamp();
1244:
1245:                return fMaxX;
1246:            }
1247:
1248:            /**
1249:             * Return the height of the last character in the text.
1250:             *
1251:             * This is used for the 'extra height' needed to display a caret at the end of the text when the
1252:             * text is empty or ends with a newline.
1253:             */
1254:            private int lastCharHeight() {
1255:                int charIndex = lastLineCharStop() - 1;
1256:                AttributeMap st = fText.characterStyleAt(charIndex);
1257:                DefaultCharacterMetric.Metric metric = fDefaultCharMetric
1258:                        .getMetricForStyle(st);
1259:
1260:                int height = metric.getAscent();
1261:                height += metric.getDescent();
1262:                height += metric.getLeading();
1263:
1264:                return height;
1265:            }
1266:
1267:            /**
1268:             * Return true if the character at pos is a paragraph separator.
1269:             */
1270:            private boolean isParaBreakBefore(int pos) {
1271:                return pos > 0
1272:                        && (fText.at(pos - 1) == '\u2029' || fText.at(pos - 1) == '\n');
1273:                // we really need to take look at this and determine what this function
1274:                // should be doing.  What I've got here right now is a temporary implementation.
1275:            }
1276:
1277:            public synchronized int minY() {
1278:
1279:                return 0;
1280:            }
1281:
1282:            /**
1283:             * Return the vertical extent of the text, in pixels.
1284:             * <p>
1285:             * This returns an approximation based on the currently formatted text.
1286:             */
1287:            public synchronized int maxY() {
1288:                checkTimeStamp();
1289:
1290:                int numChars = lastLineCharStop();
1291:
1292:                int pixHeight = fPixHeight;
1293:                if (numChars == fLTCurTextLen
1294:                        && isParaBreakBefore(fLTCurTextLen)) {
1295:                    pixHeight += lastCharHeight();
1296:                }
1297:
1298:                if (numChars != 0)
1299:                    return pixHeight * fText.length() / numChars;
1300:                else
1301:                    return 0;
1302:            }
1303:
1304:            /**
1305:             * Return the actual pixel length of the text which has been formatted.
1306:             */
1307:            public synchronized int formattedHeight() {
1308:                checkTimeStamp();
1309:                return fPixHeight;
1310:            }
1311:
1312:            /**
1313:             * There are two modes for dealing with carriage returns at the end of a line.  In the 'infinite width'
1314:             * mode, the last character is considered to have infinite width.  Thus if the point is past the 'real'
1315:             * end of the line, the offset is the position before that last character, and the offset is associated
1316:             * with that character (placement after). In the 'actual width' mode, the offset is positioned after
1317:             * that character, but still associated with it (placement before).
1318:             */
1319:
1320:            private TextOffset lineDimToOffset(TextOffset result, int line,
1321:                    int lineX, int lineY, TextOffset anchor,
1322:                    boolean infiniteMode) {
1323:                // temporarily adjust line info to remove the negative char starts used in the line table.
1324:                // then call through to the paragraph renderer to get the offset.  Don't put line end
1325:                // optimization here, let the renderer do it (perhaps it does fancy stuff with the margins).
1326:
1327:                LayoutInfo lineInfo = fLineTable[line];
1328:
1329:                result = lineInfo.pixelToOffset(fLTCurTextLen, result,
1330:                        fLineDim, lineX, lineY);
1331:
1332:                if (infiniteMode
1333:                        && (result.fOffset > lineInfo
1334:                                .getCharStart(fLTCurTextLen))
1335:                        && isParaBreakBefore(result.fOffset)
1336:                        && (anchor == null || anchor.fOffset == result.fOffset - 1)) {
1337:
1338:                    result.setOffset(result.fOffset - 1,
1339:                            TextOffset.AFTER_OFFSET);
1340:                }
1341:
1342:                return result;
1343:            }
1344:
1345:            /**
1346:             * Given a screen location p, return the offset of the character in the text nearest to p.
1347:             */
1348:            public synchronized TextOffset pointToTextOffset(TextOffset result,
1349:                    int px, int py, Point origin, TextOffset anchor,
1350:                    boolean infiniteMode) {
1351:                checkTimeStamp();
1352:                if (result == null)
1353:                    result = new TextOffset();
1354:
1355:                int fillD;
1356:
1357:                if (fHLine)
1358:                    fillD = py - origin.y;
1359:                else
1360:                    fillD = px - origin.x;
1361:
1362:                if (!fFillInc)
1363:                    fillD = -fillD;
1364:
1365:                if (fillD < 0) {
1366:                    result.setOffset(0, TextOffset.AFTER_OFFSET);
1367:                    return result;
1368:                }
1369:
1370:                formatToHeight(fillD);
1371:
1372:                if (fillD >= fPixHeight) {
1373:                    boolean bias = fLTCurTextLen == 0 ? TextOffset.AFTER_OFFSET
1374:                            : TextOffset.BEFORE_OFFSET;
1375:                    result.setOffset(fLTCurTextLen, bias);
1376:                    return result;
1377:                }
1378:
1379:                int line = findLineAt(fillD); // always a valid line
1380:                int gStart = lineGraphicStartInternal(line);
1381:
1382:                int lineX, lineY; // upper-left corner of line
1383:                if (fHLine) {
1384:                    lineX = origin.x;
1385:                    lineY = fFillInc ? origin.y + gStart : origin.y
1386:                            - (gStart + fLineTable[line].getHeight());
1387:                } else {
1388:                    lineY = origin.y;
1389:                    lineX = fFillInc ? origin.x + gStart : origin.x
1390:                            - (gStart + fLineTable[line].getHeight());
1391:                }
1392:
1393:                return lineDimToOffset(result, line, px - lineX, py - lineY,
1394:                        anchor, infiniteMode);
1395:            }
1396:
1397:            private boolean emptyParagraphAtEndOfText() {
1398:
1399:                return fLTCurTextLen > 0
1400:                        && isParagraphSeparator(fText.at(fLTCurTextLen - 1));
1401:            }
1402:
1403:            /**
1404:             * Return true if the offset designates a point on the pseudoline following a paragraph
1405:             * separator at the end of text.  This is true if the offset is the end of text
1406:             * and the last character in the text is a paragraph separator.
1407:             */
1408:            private boolean afterLastParagraph(TextOffset offset) {
1409:                return offset.fOffset == fLTCurTextLen
1410:                        && emptyParagraphAtEndOfText();
1411:            }
1412:
1413:            /**
1414:             * Given an offset, return the Rectangle bounding the caret at the offset.
1415:             * @param offset an offset into the text
1416:             * @param origin the top-left corner of the text, in the display's coordinate system
1417:             * @return a Rectangle bounding the caret.
1418:             */
1419:            public synchronized Rectangle getCaretRect(TextOffset offset,
1420:                    Point origin) {
1421:
1422:                Rectangle r = new Rectangle();
1423:                getCaretRect(r, offset, origin);
1424:                return r;
1425:            }
1426:
1427:            private void getCaretRect(Rectangle r, TextOffset offset,
1428:                    Point origin) {
1429:
1430:                checkTimeStamp();
1431:                formatToOffset(offset);
1432:
1433:                if (afterLastParagraph(offset)) {
1434:                    int pseudoLineHeight = lastCharHeight();
1435:                    if (fHLine) {
1436:                        int lineY = fFillInc ? origin.y + fPixHeight : origin.y
1437:                                - fPixHeight - pseudoLineHeight;
1438:                        r.setBounds(origin.x, lineY, 0, pseudoLineHeight);
1439:                    } else {
1440:                        int lineX = fFillInc ? origin.x + fPixHeight : origin.x
1441:                                - fPixHeight - pseudoLineHeight;
1442:                        r.setBounds(lineX, origin.y, pseudoLineHeight, 0);
1443:                    }
1444:                    return;
1445:                }
1446:
1447:                int line = getValidLineContaining(offset);
1448:
1449:                int gStart = lineGraphicStartInternal(line);
1450:
1451:                int lineX, lineY;
1452:
1453:                if (fHLine) {
1454:                    lineX = origin.x;
1455:                    if (fFillInc)
1456:                        lineY = origin.y + gStart;
1457:                    else
1458:                        lineY = origin.y
1459:                                - (gStart + fLineTable[line].getHeight());
1460:                } else {
1461:                    lineY = origin.y;
1462:                    if (fFillInc)
1463:                        lineX = origin.x + gStart;
1464:                    else
1465:                        lineX = origin.x
1466:                                - (gStart + fLineTable[line].getHeight());
1467:                }
1468:
1469:                Rectangle bounds = fLineTable[line].caretBounds(fText,
1470:                        fLTCurTextLen, fLineDim, offset.fOffset, lineX, lineY);
1471:
1472:                r.setBounds(bounds);
1473:            }
1474:
1475:            /**
1476:             * Draw the caret(s) associated with the given offset into the given Graphics.
1477:             * @param g the Graphics to draw into
1478:             * @param offset the offset in the text for which the caret is drawn
1479:             * @param origin the top-left corner of the text, in the display's coordinate system
1480:             * @param strongCaretColor the color of the strong caret
1481:             * @param weakCaretColor the color of the weak caret (if any)
1482:             */
1483:            public synchronized void drawCaret(Graphics g, TextOffset offset,
1484:                    Point origin, Color strongCaretColor, Color weakCaretColor) {
1485:
1486:                checkTimeStamp();
1487:                Graphics2D g2d = Graphics2DConversion.getGraphics2D(g);
1488:                formatToOffset(offset);
1489:
1490:                LayoutInfo line;
1491:                int gStart;
1492:
1493:                if (afterLastParagraph(offset)) {
1494:                    gStart = fPixHeight;
1495:                    line = pseudoLineInfo(null, offset.fOffset);
1496:                } else {
1497:                    int lineIndex = getValidLineContaining(offset);
1498:                    gStart = lineGraphicStartInternal(lineIndex);
1499:                    line = fLineTable[lineIndex];
1500:                }
1501:
1502:                int lineX, lineY;
1503:
1504:                if (fHLine) {
1505:                    lineX = origin.x;
1506:                    if (fFillInc)
1507:                        lineY = origin.y + gStart;
1508:                    else
1509:                        lineY = origin.y - (gStart + line.getHeight());
1510:                } else {
1511:                    lineY = origin.y;
1512:                    if (fFillInc)
1513:                        lineX = origin.x + gStart;
1514:                    else
1515:                        lineX = origin.x - (gStart + line.getHeight());
1516:                }
1517:
1518:                line
1519:                        .renderCaret(fText, fLTCurTextLen, g2d, fLineDim,
1520:                                lineX, lineY, offset.fOffset, strongCaretColor,
1521:                                weakCaretColor);
1522:            }
1523:
1524:            /**
1525:             * Given two offsets in the text, return a rectangle which encloses the lines containing the offsets.
1526:             * Offsets do not need to be ordered or nonnegative.
1527:             * @param offset1,offset2 offsets into the text
1528:             * @param origin the top-left corner of the text, in the display's coordinate system
1529:             * @returns a <tt>Rectangle</tt>, relative to <tt>origin</tt>, which encloses the lines containing the offsets
1530:             */
1531:            public synchronized Rectangle getBoundingRect(TextOffset offset1,
1532:                    TextOffset offset2, Point origin, boolean tight) {
1533:
1534:                Rectangle r = new Rectangle();
1535:                getBoundingRect(r, offset1, offset2, origin, tight);
1536:                return r;
1537:            }
1538:
1539:            /*
1540:             Transform r from "text" coordinates to "screen" coordinates.
1541:             */
1542:
1543:            private void intlRect(Point origin, Rectangle r) {
1544:
1545:                int lineOrig, fillOrig;
1546:
1547:                if (fHLine) {
1548:                    lineOrig = origin.x;
1549:                    fillOrig = origin.y;
1550:                } else {
1551:                    lineOrig = origin.y;
1552:                    fillOrig = origin.x;
1553:                }
1554:
1555:                if (fLineInc)
1556:                    r.x += lineOrig;
1557:                else
1558:                    r.x = lineOrig - (r.x + r.width);
1559:
1560:                if (fFillInc)
1561:                    r.y += fillOrig;
1562:                else
1563:                    r.y = fillOrig - (r.y + r.height);
1564:
1565:                if (!fHLine) {
1566:                    int t = r.x;
1567:                    r.x = r.y;
1568:                    r.y = t;
1569:                    t = r.width;
1570:                    r.width = r.height;
1571:                    r.height = t;
1572:                }
1573:            }
1574:
1575:            public synchronized void getBoundingRect(Rectangle r,
1576:                    TextOffset offset1, TextOffset offset2, Point origin,
1577:                    boolean tight) {
1578:                checkTimeStamp();
1579:                if (offset1.equals(offset2)) {
1580:                    getCaretRect(r, offset1, origin);
1581:                    return;
1582:                }
1583:                if (offset1.greaterThan(offset2)) {
1584:                    TextOffset t;
1585:                    t = offset1;
1586:                    offset1 = offset2;
1587:                    offset2 = t;
1588:                }
1589:
1590:                formatToOffset(offset2);
1591:
1592:                int line = getValidLineContaining(offset1);
1593:                r.y = lineGraphicStartInternal(line);
1594:
1595:                int gLimit;
1596:                boolean sameLine = false;
1597:
1598:                if (afterLastParagraph(offset2))
1599:                    gLimit = fPixHeight + lastCharHeight();
1600:                else {
1601:                    int line2 = getValidLineContaining(offset2);
1602:                    gLimit = lineGraphicLimitInternal(line2);
1603:                    sameLine = (line == line2);
1604:                }
1605:
1606:                r.height = gLimit - r.y;
1607:
1608:                if (sameLine && tight == TIGHT) {
1609:                    Rectangle rt = new Rectangle();
1610:                    getCaretRect(rt, offset1, origin);
1611:                    r.setBounds(rt);
1612:                    if (!offset1.equals(offset2)) {
1613:                        getCaretRect(rt, offset2, origin);
1614:                        r.add(rt);
1615:                    }
1616:                } else {
1617:                    r.x = fMinX;
1618:                    r.width = fMaxX - fMinX;
1619:                    intlRect(origin, r);
1620:                }
1621:
1622:                // System.out.print("gbr: " + r.x + ", " + r.y + ", " + r.width + ", " + r.height);
1623:
1624:                // System.out.println(" --> " + r.x + ", " + r.y + ", " + r.width + ", " + r.height);
1625:            }
1626:
1627:            /**
1628:             * Compute the offset resulting from moving from a previous offset in direction dir.
1629:             * For arrow keys.
1630:             * @param result the offset to modify and return.  may be null, if so a new offset is allocated, modified, and returned.
1631:             * @param previousOffset the insertion offset prior to the arrow key press.
1632:             * @param direction the direction of the arrow key (eUp, eDown, eLeft, or eRight)
1633:             * @returns new offset based on direction and previous offset.
1634:             */
1635:            public synchronized TextOffset findInsertionOffset(
1636:                    TextOffset result, TextOffset prevOffset, short dir) {
1637:                return findNewInsertionOffset(result, prevOffset, prevOffset,
1638:                        dir);
1639:            }
1640:
1641:            /**
1642:             * Transform key direction:  after this step, "left" means previous glyph, "right" means next glyph,
1643:             *"up" means previous line, "down" means next line
1644:             */
1645:            private short remapArrowKey(short dir) {
1646:
1647:                if (!fLineInc) {
1648:                    if (dir == eLeft)
1649:                        dir = eRight;
1650:                    else if (dir == eRight)
1651:                        dir = eLeft;
1652:                }
1653:
1654:                if (!fFillInc) {
1655:                    if (dir == eUp)
1656:                        dir = eDown;
1657:                    else if (dir == eDown)
1658:                        dir = eUp;
1659:                }
1660:
1661:                if (!fHLine) {
1662:                    if (dir == eLeft)
1663:                        dir = eUp;
1664:                    else if (dir == eRight)
1665:                        dir = eDown;
1666:                    else if (dir == eUp)
1667:                        dir = eLeft;
1668:                    else if (dir == eDown)
1669:                        dir = eRight;
1670:                }
1671:
1672:                return dir;
1673:            }
1674:
1675:            /**
1676:             * Compute the offset resulting from moving from a previous offset, starting at an original offset, in direction dir.
1677:             * For arrow keys.  Use this for "smart" up/down keys.
1678:             * @param result the offset to modify and return.  May be null, if so a new offset is allocated, modified, and returned.
1679:             * @param origOffset the offset at which an up-down arrow key sequence began.
1680:             * @param prevOffset the insertion offset prior to the arrow key press
1681:             * @param dir the direction of the arrow key (eUp, eDown, eLeft, or eRight)
1682:             * @returns new offset based on direction, original offset, and previous offset.
1683:             */
1684:            public synchronized TextOffset findNewInsertionOffset(
1685:                    TextOffset result, TextOffset origOffset,
1686:                    TextOffset prevOffset, short dir) {
1687:                checkTimeStamp();
1688:                if (result == null)
1689:                    result = new TextOffset();
1690:
1691:                dir = remapArrowKey(dir);
1692:
1693:                // assume that text at origOffset and prevOffset has already been formatted
1694:
1695:                if (dir == eLeft || dir == eRight) {
1696:                    formatToOffset(prevOffset);
1697:                    int line = getValidLineContaining(prevOffset);
1698:
1699:                    result.fPlacement = TextOffset.AFTER_OFFSET;
1700:                    result.fOffset = fLineTable[line].getNextOffset(
1701:                            fLTCurTextLen, prevOffset.fOffset, dir);
1702:                    if (result.fOffset < 0) {
1703:                        result.fOffset = 0;
1704:                    } else if (result.fOffset >= fLTCurTextLen) {
1705:                        result.setOffset(fLTCurTextLen,
1706:                                TextOffset.BEFORE_OFFSET);
1707:                    }
1708:                } else {
1709:                    int distOnLine;
1710:
1711:                    if (afterLastParagraph(origOffset))
1712:                        distOnLine = 0;
1713:                    else {
1714:                        int line = getValidLineContaining(origOffset);
1715:
1716:                        distOnLine = fLineTable[line]
1717:                                .strongCaretBaselinePosition(fLTCurTextLen,
1718:                                        fLineDim, origOffset.fOffset);
1719:                    }
1720:
1721:                    // get prevOffset's line
1722:                    int line;
1723:                    if (afterLastParagraph(prevOffset))
1724:                        line = lastLine() + 1;
1725:                    else {
1726:                        line = getLineContaining(prevOffset);
1727:
1728:                        if (dir == eDown
1729:                                && (line == kAfterLastLine || line == lastLine())
1730:                                && (lastLineCharStop() < fText.length())) {
1731:                            shiftTableTo(lastLine());
1732:                            formatText(lastLineCharStop(), 1,
1733:                                    Integer.MAX_VALUE, true);
1734:                            line = getLineContaining(prevOffset);
1735:                        }
1736:
1737:                        if (line == kBeforeFirstLine)
1738:                            line = 0;
1739:                        else if (line == kAfterLastLine)
1740:                            line = lastLine();
1741:                    }
1742:
1743:                    if (dir == eUp)
1744:                        line--;
1745:                    else if (dir == eDown)
1746:                        line++;
1747:                    else
1748:                        throw new IllegalArgumentException(
1749:                                "Debug: Illegal direction parameter in findNewInsertionOffset");
1750:
1751:                    if (line < 0) {
1752:                        //result.setOffset(0, TextOffset.AFTER_OFFSET);
1753:                        result.assign(prevOffset);
1754:                    } else if (line > lastLine()) {
1755:                        result.setOffset(fLTCurTextLen,
1756:                                TextOffset.BEFORE_OFFSET);
1757:                    } else {
1758:                        if (fLineTable[line] == null)
1759:                            line = (dir == eUp) ? fLTPosEnd : fLTNegStart;
1760:
1761:                        // anchor is null since we never want a position after newline.  If we used the real anchor,
1762:                        // we might not ignore the newline even though infiniteMode is true.
1763:                        lineDimToOffset(result, line, distOnLine, 0, null, true);
1764:                    }
1765:                }
1766:
1767:                // System.out.println("fnio prev: " + prevOffset + ", new: " + result);
1768:
1769:                return result;
1770:            }
1771:
1772:            public synchronized void stopBackgroundFormatting() {
1773:                checkTimeStamp();
1774:                fBgFormatAllowed = false;
1775:            }
1776:
1777:            private synchronized void enableBGFormat() {
1778:                try {
1779:                    fBgFormatAllowed = true;
1780:                    notify();
1781:                } catch (IllegalMonitorStateException e) {
1782:                }
1783:            }
1784:
1785:            private int lineIndexToNumber(int lineIndex) {
1786:
1787:                if (lineIndex <= fLTPosEnd) {
1788:                    return lineIndex;
1789:                } else {
1790:                    return lineIndex - (fLTNegStart - fLTPosEnd - 1);
1791:                }
1792:            }
1793:
1794:            private int lineNumberToIndex(int lineNumber) {
1795:
1796:                if (lineNumber <= fLTPosEnd) {
1797:                    return lineNumber;
1798:                } else {
1799:                    return lineNumber + (fLTNegStart - fLTPosEnd - 1);
1800:                }
1801:            }
1802:
1803:            private void formatToLineNumber(int lineNumber) {
1804:
1805:                while (lastLineCharStop() < fLTCurTextLen
1806:                        && lineNumber >= lineIndexToNumber(fLTSize)) {
1807:                    // could be smarter and choose larger amounts for
1808:                    // larger lines, but probably not worth the effort
1809:                    formatToHeight(fPixHeight + kPixIncrement);
1810:                }
1811:            }
1812:
1813:            private static final boolean STRICT = true;
1814:            private static final boolean LENIENT = false;
1815:
1816:            /**
1817:             * Insure that at least lineNumber lines exist, doing
1818:             * extra formatting if necessary.
1819:             * Throws exception if lineNumber is not valid.
1820:             * @param strict if STRICT, only lines [0...maxLineNumber()]
1821:             *        are permitted.  If LENIENT, maxLineNumber()+1 is
1822:             *        the greatest valid value.
1823:             */
1824:            private void validateLineNumber(int lineNumber, boolean strict) {
1825:
1826:                formatToLineNumber(lineNumber);
1827:
1828:                int maxNumber = lineIndexToNumber(fLTSize);
1829:                if (strict == STRICT) {
1830:                    maxNumber -= 1;
1831:                }
1832:
1833:                if (lineNumber > maxNumber + 1
1834:                        || (lineNumber == maxNumber + 1 && !emptyParagraphAtEndOfText())) {
1835:                    throw new IllegalArgumentException("Invalid line number: "
1836:                            + lineNumber);
1837:                }
1838:            }
1839:
1840:            public synchronized int getLineCount() {
1841:
1842:                // format all text:
1843:                formatToHeight(Integer.MAX_VALUE);
1844:
1845:                int lineCount = lineIndexToNumber(fLTSize);
1846:
1847:                if (emptyParagraphAtEndOfText()) {
1848:                    lineCount += 1;
1849:                }
1850:
1851:                return lineCount;
1852:            }
1853:
1854:            public synchronized int lineContaining(int charIndex) {
1855:
1856:                formatToOffset(charIndex, TextOffset.AFTER_OFFSET);
1857:
1858:                boolean placement = TextOffset.AFTER_OFFSET;
1859:                if (charIndex == fLTCurTextLen && charIndex > 0) {
1860:                    placement = emptyParagraphAtEndOfText() ? TextOffset.AFTER_OFFSET
1861:                            : TextOffset.BEFORE_OFFSET;
1862:                }
1863:
1864:                return lineContaining(charIndex, placement);
1865:            }
1866:
1867:            public synchronized int lineContaining(TextOffset offset) {
1868:
1869:                formatToOffset(offset);
1870:
1871:                if (afterLastParagraph(offset)) {
1872:                    return lineIndexToNumber(fLTSize);
1873:                }
1874:
1875:                return lineContaining(offset.fOffset, offset.fPlacement);
1876:            }
1877:
1878:            private int lineContaining(int off, boolean placement) {
1879:
1880:                int line = off == 0 ? 0 : getLineContaining(off, placement);
1881:
1882:                if (line == kAfterLastLine) {
1883:                    line = fLTSize;
1884:                } else if (line == kBeforeFirstLine) {
1885:                    throw new Error(
1886:                            "lineContaining got invalid result from getLineContaining().");
1887:                }
1888:
1889:                return lineIndexToNumber(line);
1890:            }
1891:
1892:            public synchronized int lineRangeLow(int lineNumber) {
1893:
1894:                validateLineNumber(lineNumber, STRICT);
1895:                int index = lineNumberToIndex(lineNumber);
1896:
1897:                if (index == fLTSize) {
1898:                    if (emptyParagraphAtEndOfText()) {
1899:                        return lastLineCharStop();
1900:                    }
1901:                }
1902:
1903:                if (index >= fLTSize) {
1904:                    throw new IllegalArgumentException("lineNumber is invalid.");
1905:                } else {
1906:                    return lineCharStartInternal(index);
1907:                }
1908:            }
1909:
1910:            public synchronized int lineRangeLimit(int lineNumber) {
1911:
1912:                validateLineNumber(lineNumber, STRICT);
1913:                int index = lineNumberToIndex(lineNumber);
1914:
1915:                if (index == fLTSize) {
1916:                    if (emptyParagraphAtEndOfText()) {
1917:                        return lastLineCharStop();
1918:                    }
1919:                }
1920:
1921:                if (index >= fLTSize) {
1922:                    throw new IllegalArgumentException("lineNumber is invalid.");
1923:                } else {
1924:                    return lineCharLimitInternal(index);
1925:                }
1926:            }
1927:
1928:            /**
1929:             * Return the number of the line at the given graphic height.
1930:             * If height is greater than full height, return line count.
1931:             */
1932:            public synchronized int lineAtHeight(int height) {
1933:
1934:                if (height >= fPixHeight) {
1935:
1936:                    int line = getLineCount();
1937:                    if (height < fFullPixHeight) {
1938:                        line -= 1;
1939:                    }
1940:                    return line;
1941:                } else if (height < 0) {
1942:                    return -1;
1943:                } else {
1944:                    return lineIndexToNumber(findLineAt(height));
1945:                }
1946:            }
1947:
1948:            public synchronized int lineGraphicStart(int lineNumber) {
1949:
1950:                checkTimeStamp();
1951:                validateLineNumber(lineNumber, LENIENT);
1952:
1953:                int index = lineNumberToIndex(lineNumber);
1954:
1955:                if (index < fLTSize) {
1956:                    return lineGraphicStartInternal(index);
1957:                } else {
1958:                    if (index == fLTSize + 1) {
1959:                        return fFullPixHeight;
1960:                    } else {
1961:                        return fPixHeight;
1962:                    }
1963:                }
1964:            }
1965:
1966:            public synchronized boolean lineIsLeftToRight(int lineNumber) {
1967:
1968:                validateLineNumber(lineNumber, STRICT);
1969:
1970:                int index = lineNumberToIndex(lineNumber);
1971:
1972:                if (index < fLTSize) {
1973:                    return fLineTable[index].isLeftToRight();
1974:                } else {
1975:                    AttributeMap st = fText.paragraphStyleAt(fLTCurTextLen);
1976:                    return !TextAttribute.RUN_DIRECTION_RTL.equals(st
1977:                            .get(TextAttribute.RUN_DIRECTION));
1978:                }
1979:            }
1980:
1981:            /**
1982:             * Number of pixels by which to advance formatting in the background.
1983:             */
1984:            private static final int kPixIncrement = 100;
1985:
1986:            /**
1987:             * Time to sleep between background formatting operations.
1988:             */
1989:            private static final int kInterval = 100;
1990:
1991:            /**
1992:             * Perform periodic background formatting.
1993:             */
1994:            public void run() {
1995:                while (true) {
1996:                    synchronized (this ) {
1997:                        while (!fBgFormatAllowed) {
1998:                            try {
1999:                                wait();
2000:                            } catch (InterruptedException e) {
2001:                            }
2002:                        }
2003:
2004:                        checkTimeStamp();
2005:                        formatToHeight(fPixHeight + kPixIncrement);
2006:
2007:                        if (lastLineCharStop() == fLTCurTextLen) {
2008:                            stopBackgroundFormatting();
2009:                        }
2010:                    }
2011:
2012:                    try {
2013:                        Thread.sleep(kInterval);
2014:                    } catch (InterruptedException e) {
2015:                    }
2016:                }
2017:            }
2018:
2019:            private ParagraphRenderer getRendererFor(AttributeMap s) {
2020:
2021:                // Note:  eventually we could let clients put their own renderers
2022:                // on the text.
2023:                BidiParagraphRenderer renderer = (BidiParagraphRenderer) fRendererCache
2024:                        .get(s);
2025:                if (renderer == null) {
2026:                    renderer = new BidiParagraphRenderer(fDefaultValues
2027:                            .addAttributes(s), fDefaultCharMetric);
2028:                    fRendererCache.put(s, renderer);
2029:                }
2030:                return renderer;
2031:            }
2032:
2033:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.