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

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


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         */
0017:        /**
0018:         * @author Oleg V. Khaschansky
0019:         * @version $Revision$
0020:         *
0021:         */package org.apache.harmony.awt.gl.font;
0022:
0023:        import java.awt.*;
0024:        import java.awt.font.*;
0025:        import java.awt.geom.Rectangle2D;
0026:        import java.awt.geom.GeneralPath;
0027:        import java.awt.geom.AffineTransform;
0028:        import java.awt.geom.Point2D; // XXX - TODO - bidi not implemented yet
0029:        //import java.text.Bidi;
0030:        import java.util.Arrays;
0031:
0032:        import org.apache.harmony.awt.internal.nls.Messages;
0033:
0034:        /**
0035:         * Date: Apr 25, 2005
0036:         * Time: 4:33:18 PM
0037:         *
0038:         * This class contains the implementation of the behavior of the
0039:         * text run segment with constant text attributes and direction.
0040:         */
0041:        public class TextRunSegmentImpl {
0042:
0043:            /**
0044:             * This class contains basic information required for creation
0045:             * of the glyph-based text run segment.
0046:             */
0047:            public static class TextSegmentInfo {
0048:                // XXX - TODO - bidi not implemented yet
0049:                //Bidi bidi;
0050:
0051:                Font font;
0052:                FontRenderContext frc;
0053:
0054:                char text[];
0055:
0056:                int start;
0057:                int end;
0058:                int length;
0059:
0060:                int flags = 0;
0061:
0062:                byte level = 0;
0063:
0064:                TextSegmentInfo(byte level, Font font, FontRenderContext frc,
0065:                        char text[], int start, int end) {
0066:                    this .font = font;
0067:                    this .frc = frc;
0068:                    this .text = text;
0069:                    this .start = start;
0070:                    this .end = end;
0071:                    this .level = level;
0072:                    length = end - start;
0073:                }
0074:            }
0075:
0076:            /**
0077:             * This class represents a simple text segment backed by the glyph vector
0078:             */
0079:            public static class TextRunSegmentCommon extends TextRunSegment {
0080:                TextSegmentInfo info;
0081:                private GlyphVector gv;
0082:                private float advanceIncrements[];
0083:                private int char2glyph[];
0084:                private GlyphJustificationInfo gjis[]; // Glyph justification info
0085:
0086:                TextRunSegmentCommon(TextSegmentInfo i,
0087:                        TextDecorator.Decoration d) {
0088:                    // XXX - todo - check support bidi
0089:                    i.flags &= ~0x09; // Clear bidi flags
0090:
0091:                    if ((i.level & 0x1) != 0) {
0092:                        i.flags |= Font.LAYOUT_RIGHT_TO_LEFT;
0093:                    }
0094:
0095:                    info = i;
0096:                    this .decoration = d;
0097:
0098:                    LineMetrics lm = i.font.getLineMetrics(i.text, i.start,
0099:                            i.end, i.frc);
0100:                    this .metrics = new BasicMetrics(lm, i.font);
0101:
0102:                    if (lm.getNumChars() != i.length) { // XXX todo - This should be handled
0103:                        // awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
0104:                        throw new UnsupportedOperationException(Messages
0105:                                .getString("awt.41")); //$NON-NLS-1$
0106:                    }
0107:                }
0108:
0109:                @Override
0110:                public Object clone() {
0111:                    return new TextRunSegmentCommon(info, decoration);
0112:                }
0113:
0114:                /**
0115:                 * Creates glyph vector from the managed text if needed
0116:                 * @return glyph vector
0117:                 */
0118:                private GlyphVector getGlyphVector() {
0119:                    if (gv == null) {
0120:                        gv = info.font.layoutGlyphVector(info.frc, info.text,
0121:                                info.start, info.end - info.start, // NOTE: This parameter violates
0122:                                // spec, it is count,
0123:                                // not limit as spec states
0124:                                info.flags);
0125:                    }
0126:
0127:                    return gv;
0128:                }
0129:
0130:                /**
0131:                 * Renders this text run segment
0132:                 * @param g2d - graphics to render to
0133:                 * @param xOffset - X offset from the graphics origin to the
0134:                 * origin of the text layout
0135:                 * @param yOffset - Y offset from the graphics origin to the
0136:                 * origin of the text layout
0137:                 */
0138:                @Override
0139:                void draw(Graphics2D g2d, float xOffset, float yOffset) {
0140:                    if (decoration == null) {
0141:                        g2d.drawGlyphVector(getGlyphVector(), xOffset + x,
0142:                                yOffset + y);
0143:                    } else {
0144:                        TextDecorator.prepareGraphics(this , g2d, xOffset,
0145:                                yOffset);
0146:                        g2d.drawGlyphVector(getGlyphVector(), xOffset + x,
0147:                                yOffset + y);
0148:                        TextDecorator.drawTextDecorations(this , g2d, xOffset,
0149:                                yOffset);
0150:                        TextDecorator.restoreGraphics(decoration, g2d);
0151:                    }
0152:                }
0153:
0154:                /**
0155:                 * Returns visual bounds of this segment
0156:                 * @return visual bounds
0157:                 */
0158:                @Override
0159:                Rectangle2D getVisualBounds() {
0160:                    if (visualBounds == null) {
0161:                        visualBounds = TextDecorator.extendVisualBounds(this ,
0162:                                getGlyphVector().getVisualBounds(), decoration);
0163:
0164:                        visualBounds.setRect(x + visualBounds.getX(), y
0165:                                + visualBounds.getY(), visualBounds.getWidth(),
0166:                                visualBounds.getHeight());
0167:                    }
0168:
0169:                    return (Rectangle2D) visualBounds.clone();
0170:                }
0171:
0172:                /**
0173:                 * Returns logical bounds of this segment
0174:                 * @return logical bounds
0175:                 */
0176:                @Override
0177:                Rectangle2D getLogicalBounds() {
0178:                    if (logicalBounds == null) {
0179:                        logicalBounds = getGlyphVector().getLogicalBounds();
0180:
0181:                        logicalBounds.setRect(x + logicalBounds.getX(), y
0182:                                + logicalBounds.getY(), logicalBounds
0183:                                .getWidth(), logicalBounds.getHeight());
0184:                    }
0185:
0186:                    return (Rectangle2D) logicalBounds.clone();
0187:                }
0188:
0189:                @Override
0190:                float getAdvance() {
0191:                    return (float) getLogicalBounds().getWidth();
0192:                }
0193:
0194:                /**
0195:                 * Attempts to map each character to the corresponding advance increment
0196:                 */
0197:                void initAdvanceMapping() {
0198:                    GlyphVector gv = getGlyphVector();
0199:                    int charIndicies[] = gv.getGlyphCharIndices(0, gv
0200:                            .getNumGlyphs(), null);
0201:                    advanceIncrements = new float[info.length];
0202:
0203:                    for (int i = 0; i < charIndicies.length; i++) {
0204:                        advanceIncrements[charIndicies[i]] = gv
0205:                                .getGlyphMetrics(i).getAdvance();
0206:                    }
0207:                }
0208:
0209:                /**
0210:                 * Calculates advance delta between two characters
0211:                 * @param start - 1st position
0212:                 * @param end - 2nd position
0213:                 * @return advance increment between specified positions
0214:                 */
0215:                @Override
0216:                float getAdvanceDelta(int start, int end) {
0217:                    // Get coordinates in the segment context
0218:                    start -= info.start;
0219:                    end -= info.start;
0220:
0221:                    if (advanceIncrements == null) {
0222:                        initAdvanceMapping();
0223:                    }
0224:
0225:                    if (start < 0) {
0226:                        start = 0;
0227:                    }
0228:                    if (end > info.length) {
0229:                        end = info.length;
0230:                    }
0231:
0232:                    float sum = 0;
0233:                    for (int i = start; i < end; i++) {
0234:                        sum += advanceIncrements[i];
0235:                    }
0236:
0237:                    return sum;
0238:                }
0239:
0240:                /**
0241:                 * Calculates index of the character which advance is equal to
0242:                 * the given. If the given advance is greater then the segment
0243:                 * advance it returns the position after the last character.
0244:                 * @param advance - given advance
0245:                 * @param start - character, from which to start measuring advance
0246:                 * @return character index
0247:                 */
0248:                @Override
0249:                int getCharIndexFromAdvance(float advance, int start) {
0250:                    // XXX - todo - probably, possible to optimize
0251:                    // Add check if the given advance is greater then
0252:                    // the segment advance in the beginning. In this case
0253:                    // we don't need to run through all increments
0254:                    if (advanceIncrements == null) {
0255:                        initAdvanceMapping();
0256:                    }
0257:
0258:                    start -= info.start;
0259:
0260:                    if (start < 0) {
0261:                        start = 0;
0262:                    }
0263:
0264:                    int i = start;
0265:                    for (; i < info.length; i++) {
0266:                        advance -= advanceIncrements[i];
0267:                        if (advance < 0) {
0268:                            break;
0269:                        }
0270:                    }
0271:
0272:                    return i + info.start;
0273:                }
0274:
0275:                @Override
0276:                int getStart() {
0277:                    return info.start;
0278:                }
0279:
0280:                @Override
0281:                int getEnd() {
0282:                    return info.end;
0283:                }
0284:
0285:                @Override
0286:                int getLength() {
0287:                    return info.length;
0288:                }
0289:
0290:                /**
0291:                 * Attempts to create mapping of the characters to glyphs in the glyph vector.
0292:                 * @return array where for each character index stored corresponding glyph index
0293:                 */
0294:                private int[] getChar2Glyph() {
0295:                    if (char2glyph == null) {
0296:                        GlyphVector gv = getGlyphVector();
0297:                        char2glyph = new int[info.length];
0298:                        Arrays.fill(char2glyph, -1);
0299:
0300:                        // Fill glyph indicies for first characters corresponding to each glyph
0301:                        int charIndicies[] = gv.getGlyphCharIndices(0, gv
0302:                                .getNumGlyphs(), null);
0303:                        for (int i = 0; i < charIndicies.length; i++) {
0304:                            char2glyph[charIndicies[i]] = i;
0305:                        }
0306:
0307:                        // If several characters corresponds to one glyph, create mapping for them
0308:                        // Suppose that these characters are going all together
0309:                        int currIndex = 0;
0310:                        for (int i = 0; i < char2glyph.length; i++) {
0311:                            if (char2glyph[i] < 0) {
0312:                                char2glyph[i] = currIndex;
0313:                            } else {
0314:                                currIndex = char2glyph[i];
0315:                            }
0316:                        }
0317:                    }
0318:
0319:                    return char2glyph;
0320:                }
0321:
0322:                /**
0323:                 * Creates black box bounds shape for the specified range
0324:                 * @param start - range sart
0325:                 * @param limit - range end
0326:                 * @return black box bounds shape
0327:                 */
0328:                @Override
0329:                Shape getCharsBlackBoxBounds(int start, int limit) {
0330:                    start -= info.start;
0331:                    limit -= info.start;
0332:
0333:                    if (limit > info.length) {
0334:                        limit = info.length;
0335:                    }
0336:
0337:                    GeneralPath result = new GeneralPath();
0338:
0339:                    int glyphIndex = 0;
0340:
0341:                    for (int i = start; i < limit; i++) {
0342:                        glyphIndex = getChar2Glyph()[i];
0343:                        result.append(getGlyphVector().getGlyphVisualBounds(
0344:                                glyphIndex), false);
0345:                    }
0346:
0347:                    // Shift to the segment's coordinates
0348:                    result
0349:                            .transform(AffineTransform.getTranslateInstance(x,
0350:                                    y));
0351:
0352:                    return result;
0353:                }
0354:
0355:                /**
0356:                 * Calculates position of the character on the screen
0357:                 * @param index - character index
0358:                 * @return X coordinate of the character position
0359:                 */
0360:                @Override
0361:                float getCharPosition(int index) {
0362:                    index -= info.start;
0363:
0364:                    if (index > info.length) {
0365:                        index = info.length;
0366:                    }
0367:
0368:                    float result = 0;
0369:
0370:                    int glyphIndex = getChar2Glyph()[index];
0371:                    result = (float) getGlyphVector().getGlyphPosition(
0372:                            glyphIndex).getX();
0373:
0374:                    // Shift to the segment's coordinates
0375:                    result += x;
0376:
0377:                    return result;
0378:                }
0379:
0380:                /**
0381:                 * Returns the advance of the individual character
0382:                 * @param index - character index
0383:                 * @return character advance
0384:                 */
0385:                @Override
0386:                float getCharAdvance(int index) {
0387:                    if (advanceIncrements == null) {
0388:                        initAdvanceMapping();
0389:                    }
0390:
0391:                    return advanceIncrements[index - this .getStart()];
0392:                }
0393:
0394:                /**
0395:                 * Returns the outline shape
0396:                 * @return outline
0397:                 */
0398:                @Override
0399:                Shape getOutline() {
0400:                    AffineTransform t = AffineTransform.getTranslateInstance(x,
0401:                            y);
0402:                    return t.createTransformedShape(TextDecorator
0403:                            .extendOutline(this , getGlyphVector().getOutline(),
0404:                                    decoration));
0405:                }
0406:
0407:                /**
0408:                 * Checks if the character doesn't contribute to the text advance
0409:                 * @param index - character index
0410:                 * @return true if the character has zero advance
0411:                 */
0412:                @Override
0413:                boolean charHasZeroAdvance(int index) {
0414:                    if (advanceIncrements == null) {
0415:                        initAdvanceMapping();
0416:                    }
0417:
0418:                    return advanceIncrements[index - this .getStart()] == 0;
0419:                }
0420:
0421:                /**
0422:                 * Creates text hit info from the hit position
0423:                 * @param hitX - X coordinate relative to the origin of the layout
0424:                 * @param hitY - Y coordinate relative to the origin of the layout
0425:                 * @return hit info
0426:                 */
0427:                @Override
0428:                TextHitInfo hitTest(float hitX, float hitY) {
0429:                    hitX -= x;
0430:
0431:                    float glyphPositions[] = getGlyphVector()
0432:                            .getGlyphPositions(0, info.length + 1, null);
0433:
0434:                    int glyphIdx;
0435:                    boolean leading = false;
0436:                    for (glyphIdx = 1; glyphIdx <= info.length; glyphIdx++) {
0437:                        if (glyphPositions[(glyphIdx) * 2] >= hitX) {
0438:                            float advance = glyphPositions[(glyphIdx) * 2]
0439:                                    - glyphPositions[(glyphIdx - 1) * 2];
0440:                            leading = glyphPositions[(glyphIdx - 1) * 2]
0441:                                    + advance / 2 > hitX ? true : false;
0442:                            glyphIdx--;
0443:                            break;
0444:                        }
0445:                    }
0446:
0447:                    if (glyphIdx == info.length) {
0448:                        glyphIdx--;
0449:                    }
0450:
0451:                    int charIdx = getGlyphVector().getGlyphCharIndex(glyphIdx);
0452:
0453:                    return (leading) ^ ((info.level & 0x1) == 0x1) ? TextHitInfo
0454:                            .leading(charIdx + info.start)
0455:                            : TextHitInfo.trailing(charIdx + info.start);
0456:                }
0457:
0458:                /**
0459:                 * Collects GlyphJustificationInfo objects from the glyph vector
0460:                 * @return array of all GlyphJustificationInfo objects
0461:                 */
0462:                private GlyphJustificationInfo[] getGlyphJustificationInfos() {
0463:                    if (gjis == null) {
0464:                        GlyphVector gv = getGlyphVector();
0465:                        int nGlyphs = gv.getNumGlyphs();
0466:                        int charIndicies[] = gv.getGlyphCharIndices(0, nGlyphs,
0467:                                null);
0468:                        gjis = new GlyphJustificationInfo[nGlyphs];
0469:
0470:                        // Patch: temporary patch, getGlyphJustificationInfo is not implemented
0471:                        float fontSize = info.font.getSize2D();
0472:                        GlyphJustificationInfo defaultInfo = new GlyphJustificationInfo(
0473:                                0, // weight
0474:                                false, GlyphJustificationInfo.PRIORITY_NONE,
0475:                                0,
0476:                                0, // grow
0477:                                false, GlyphJustificationInfo.PRIORITY_NONE, 0,
0478:                                0); // shrink
0479:                        GlyphJustificationInfo spaceInfo = new GlyphJustificationInfo(
0480:                                fontSize, // weight
0481:                                true,
0482:                                GlyphJustificationInfo.PRIORITY_WHITESPACE,
0483:                                0,
0484:                                fontSize, // grow
0485:                                true,
0486:                                GlyphJustificationInfo.PRIORITY_WHITESPACE, 0,
0487:                                fontSize); // shrink
0488:
0489:                        ////////
0490:                        // Temporary patch, getGlyphJustificationInfo is not implemented
0491:                        for (int i = 0; i < nGlyphs; i++) {
0492:                            //gjis[i] = getGlyphVector().getGlyphJustificationInfo(i);
0493:
0494:                            char c = info.text[charIndicies[i] + info.start];
0495:                            if (Character.isWhitespace(c)) {
0496:                                gjis[i] = spaceInfo;
0497:                            } else {
0498:                                gjis[i] = defaultInfo;
0499:                            }
0500:                            // End patch
0501:                        }
0502:                    }
0503:
0504:                    return gjis;
0505:                }
0506:
0507:                /**
0508:                 * Collects justification information into JustificationInfo object
0509:                 * @param jInfo - JustificationInfo object
0510:                 */
0511:                @Override
0512:                void updateJustificationInfo(
0513:                        TextRunBreaker.JustificationInfo jInfo) {
0514:                    int lastChar = Math.min(jInfo.lastIdx, info.end)
0515:                            - info.start;
0516:                    boolean haveFirst = info.start <= jInfo.firstIdx;
0517:                    boolean haveLast = info.end >= (jInfo.lastIdx + 1);
0518:
0519:                    int prevGlyphIdx = -1;
0520:                    int currGlyphIdx;
0521:
0522:                    if (jInfo.grow) { // Check how much we can grow/shrink on current priority level
0523:                        for (int i = 0; i < lastChar; i++) {
0524:                            currGlyphIdx = getChar2Glyph()[i];
0525:
0526:                            if (currGlyphIdx == prevGlyphIdx) {
0527:                                // Several chars could be represented by one glyph,
0528:                                // suppose they are contiguous
0529:                                continue;
0530:                            }
0531:                            prevGlyphIdx = currGlyphIdx;
0532:
0533:                            GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
0534:                            if (gji.growPriority == jInfo.priority) {
0535:                                jInfo.weight += gji.weight * 2;
0536:                                jInfo.growLimit += gji.growLeftLimit;
0537:                                jInfo.growLimit += gji.growRightLimit;
0538:                                if (gji.growAbsorb) {
0539:                                    jInfo.absorbedWeight += gji.weight * 2;
0540:                                }
0541:                            }
0542:                        }
0543:                    } else {
0544:                        for (int i = 0; i < lastChar; i++) {
0545:                            currGlyphIdx = getChar2Glyph()[i];
0546:                            if (currGlyphIdx == prevGlyphIdx) {
0547:                                continue;
0548:                            }
0549:                            prevGlyphIdx = currGlyphIdx;
0550:
0551:                            GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
0552:                            if (gji.shrinkPriority == jInfo.priority) {
0553:                                jInfo.weight += gji.weight * 2;
0554:                                jInfo.growLimit -= gji.shrinkLeftLimit;
0555:                                jInfo.growLimit -= gji.shrinkRightLimit;
0556:                                if (gji.shrinkAbsorb) {
0557:                                    jInfo.absorbedWeight += gji.weight * 2;
0558:                                }
0559:                            }
0560:                        }
0561:                    }
0562:
0563:                    if (haveFirst) { // Don't add padding before first char
0564:                        GlyphJustificationInfo gji = getGlyphJustificationInfos()[getChar2Glyph()[0]];
0565:                        jInfo.weight -= gji.weight;
0566:                        if (jInfo.grow) {
0567:                            jInfo.growLimit -= gji.growLeftLimit;
0568:                            if (gji.growAbsorb) {
0569:                                jInfo.absorbedWeight -= gji.weight;
0570:                            }
0571:                        } else {
0572:                            jInfo.growLimit += gji.shrinkLeftLimit;
0573:                            if (gji.shrinkAbsorb) {
0574:                                jInfo.absorbedWeight -= gji.weight;
0575:                            }
0576:                        }
0577:                    }
0578:
0579:                    if (haveLast) { // Don't add padding after last char
0580:                        GlyphJustificationInfo gji = getGlyphJustificationInfos()[getChar2Glyph()[lastChar]];
0581:                        jInfo.weight -= gji.weight;
0582:                        if (jInfo.grow) {
0583:                            jInfo.growLimit -= gji.growRightLimit;
0584:                            if (gji.growAbsorb) {
0585:                                jInfo.absorbedWeight -= gji.weight;
0586:                            }
0587:                        } else {
0588:                            jInfo.growLimit += gji.shrinkRightLimit;
0589:                            if (gji.shrinkAbsorb) {
0590:                                jInfo.absorbedWeight -= gji.weight;
0591:                            }
0592:                        }
0593:                    }
0594:                }
0595:
0596:                /**
0597:                 * Performs justification of the segment.
0598:                 * Updates positions of individual characters.
0599:                 * @param jInfos - justification information, gathered by the previous passes
0600:                 * @return amount of growth or shrink of the segment
0601:                 */
0602:                @Override
0603:                float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
0604:                    int lastPriority = jInfos[jInfos.length - 1] == null ? -1
0605:                            : jInfos[jInfos.length - 1].priority;
0606:
0607:                    // Get the highest priority
0608:                    int highestPriority = 0;
0609:                    for (; highestPriority < jInfos.length; highestPriority++) {
0610:                        if (jInfos[highestPriority] != null) {
0611:                            break;
0612:                        }
0613:                    }
0614:
0615:                    if (highestPriority == jInfos.length) {
0616:                        return 0;
0617:                    }
0618:
0619:                    TextRunBreaker.JustificationInfo firstInfo = jInfos[highestPriority];
0620:                    TextRunBreaker.JustificationInfo lastInfo = lastPriority > 0 ? jInfos[lastPriority]
0621:                            : null;
0622:
0623:                    boolean haveFirst = info.start <= firstInfo.firstIdx;
0624:                    boolean haveLast = info.end >= (firstInfo.lastIdx + 1);
0625:
0626:                    // Here we suppose that GLYPHS are ordered LEFT TO RIGHT
0627:                    int firstGlyph = haveFirst ? getChar2Glyph()[firstInfo.firstIdx
0628:                            - info.start]
0629:                            : getChar2Glyph()[0];
0630:
0631:                    int lastGlyph = haveLast ? getChar2Glyph()[firstInfo.lastIdx
0632:                            - info.start]
0633:                            : getChar2Glyph()[info.length - 1];
0634:                    if (haveLast) {
0635:                        lastGlyph--;
0636:                    }
0637:
0638:                    TextRunBreaker.JustificationInfo currInfo;
0639:                    float glyphOffset = 0;
0640:                    float positionIncrement = 0;
0641:                    float sideIncrement = 0;
0642:
0643:                    if (haveFirst) { // Don't add padding before first char
0644:                        GlyphJustificationInfo gji = getGlyphJustificationInfos()[firstGlyph];
0645:                        currInfo = jInfos[gji.growPriority];
0646:                        if (currInfo != null) {
0647:                            if (currInfo.useLimits) {
0648:                                if (currInfo.absorb) {
0649:                                    glyphOffset += gji.weight
0650:                                            * currInfo.absorbedGapPerUnit;
0651:                                } else if (lastInfo != null
0652:                                        && lastInfo.priority == currInfo.priority) {
0653:                                    glyphOffset += gji.weight
0654:                                            * lastInfo.absorbedGapPerUnit;
0655:                                }
0656:                                glyphOffset += firstInfo.grow ? gji.growRightLimit
0657:                                        : -gji.shrinkRightLimit;
0658:                            } else {
0659:                                glyphOffset += gji.weight * currInfo.gapPerUnit;
0660:                            }
0661:                        }
0662:
0663:                        firstGlyph++;
0664:                    }
0665:
0666:                    if (firstInfo.grow) {
0667:                        for (int i = firstGlyph; i <= lastGlyph; i++) {
0668:                            GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
0669:                            currInfo = jInfos[gji.growPriority];
0670:                            if (currInfo == null) {
0671:                                // We still have to increment glyph position
0672:                                Point2D glyphPos = getGlyphVector()
0673:                                        .getGlyphPosition(i);
0674:                                glyphPos.setLocation(glyphPos.getX()
0675:                                        + glyphOffset, glyphPos.getY());
0676:                                getGlyphVector().setGlyphPosition(i, glyphPos);
0677:
0678:                                continue;
0679:                            }
0680:
0681:                            if (currInfo.useLimits) {
0682:                                glyphOffset += gji.growLeftLimit;
0683:                                if (currInfo.absorb) {
0684:                                    sideIncrement = gji.weight
0685:                                            * currInfo.absorbedGapPerUnit;
0686:                                    glyphOffset += sideIncrement;
0687:                                    positionIncrement = glyphOffset;
0688:                                    glyphOffset += sideIncrement;
0689:                                } else if (lastInfo != null
0690:                                        && lastInfo.priority == currInfo.priority) {
0691:                                    sideIncrement = gji.weight
0692:                                            * lastInfo.absorbedGapPerUnit;
0693:                                    glyphOffset += sideIncrement;
0694:                                    positionIncrement = glyphOffset;
0695:                                    glyphOffset += sideIncrement;
0696:                                } else {
0697:                                    positionIncrement = glyphOffset;
0698:                                }
0699:                                glyphOffset += gji.growRightLimit;
0700:                            } else {
0701:                                sideIncrement = gji.weight
0702:                                        * currInfo.gapPerUnit;
0703:                                glyphOffset += sideIncrement;
0704:                                positionIncrement = glyphOffset;
0705:                                glyphOffset += sideIncrement;
0706:                            }
0707:
0708:                            Point2D glyphPos = getGlyphVector()
0709:                                    .getGlyphPosition(i);
0710:                            glyphPos.setLocation(glyphPos.getX()
0711:                                    + positionIncrement, glyphPos.getY());
0712:                            getGlyphVector().setGlyphPosition(i, glyphPos);
0713:                        }
0714:                    } else {
0715:                        for (int i = firstGlyph; i <= lastGlyph; i++) {
0716:                            GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
0717:                            currInfo = jInfos[gji.shrinkPriority];
0718:                            if (currInfo == null) {
0719:                                // We still have to increment glyph position
0720:                                Point2D glyphPos = getGlyphVector()
0721:                                        .getGlyphPosition(i);
0722:                                glyphPos.setLocation(glyphPos.getX()
0723:                                        + glyphOffset, glyphPos.getY());
0724:                                getGlyphVector().setGlyphPosition(i, glyphPos);
0725:
0726:                                continue;
0727:                            }
0728:
0729:                            if (currInfo.useLimits) {
0730:                                glyphOffset -= gji.shrinkLeftLimit;
0731:                                if (currInfo.absorb) {
0732:                                    sideIncrement = gji.weight
0733:                                            * currInfo.absorbedGapPerUnit;
0734:                                    glyphOffset += sideIncrement;
0735:                                    positionIncrement = glyphOffset;
0736:                                    glyphOffset += sideIncrement;
0737:                                } else if (lastInfo != null
0738:                                        && lastInfo.priority == currInfo.priority) {
0739:                                    sideIncrement = gji.weight
0740:                                            * lastInfo.absorbedGapPerUnit;
0741:                                    glyphOffset += sideIncrement;
0742:                                    positionIncrement = glyphOffset;
0743:                                    glyphOffset += sideIncrement;
0744:                                } else {
0745:                                    positionIncrement = glyphOffset;
0746:                                }
0747:                                glyphOffset -= gji.shrinkRightLimit;
0748:                            } else {
0749:                                sideIncrement = gji.weight
0750:                                        * currInfo.gapPerUnit;
0751:                                glyphOffset += sideIncrement;
0752:                                positionIncrement = glyphOffset;
0753:                                glyphOffset += sideIncrement;
0754:                            }
0755:
0756:                            Point2D glyphPos = getGlyphVector()
0757:                                    .getGlyphPosition(i);
0758:                            glyphPos.setLocation(glyphPos.getX()
0759:                                    + positionIncrement, glyphPos.getY());
0760:                            getGlyphVector().setGlyphPosition(i, glyphPos);
0761:                        }
0762:                    }
0763:
0764:                    if (haveLast) { // Don't add padding after last char
0765:                        lastGlyph++;
0766:
0767:                        GlyphJustificationInfo gji = getGlyphJustificationInfos()[lastGlyph];
0768:                        currInfo = jInfos[gji.growPriority];
0769:
0770:                        if (currInfo != null) {
0771:                            if (currInfo.useLimits) {
0772:                                glyphOffset += firstInfo.grow ? gji.growLeftLimit
0773:                                        : -gji.shrinkLeftLimit;
0774:                                if (currInfo.absorb) {
0775:                                    glyphOffset += gji.weight
0776:                                            * currInfo.absorbedGapPerUnit;
0777:                                } else if (lastInfo != null
0778:                                        && lastInfo.priority == currInfo.priority) {
0779:                                    glyphOffset += gji.weight
0780:                                            * lastInfo.absorbedGapPerUnit;
0781:                                }
0782:                            } else {
0783:                                glyphOffset += gji.weight * currInfo.gapPerUnit;
0784:                            }
0785:                        }
0786:
0787:                        // Ajust positions of all glyphs after last glyph
0788:                        for (int i = lastGlyph; i < getGlyphVector()
0789:                                .getNumGlyphs() + 1; i++) {
0790:                            Point2D glyphPos = getGlyphVector()
0791:                                    .getGlyphPosition(i);
0792:                            glyphPos.setLocation(glyphPos.getX() + glyphOffset,
0793:                                    glyphPos.getY());
0794:                            getGlyphVector().setGlyphPosition(i, glyphPos);
0795:                        }
0796:                    } else { // Update position after last glyph in glyph vector -
0797:                        // to get correct advance for it
0798:                        Point2D glyphPos = getGlyphVector().getGlyphPosition(
0799:                                lastGlyph + 1);
0800:                        glyphPos.setLocation(glyphPos.getX() + glyphOffset,
0801:                                glyphPos.getY());
0802:                        getGlyphVector().setGlyphPosition(lastGlyph + 1,
0803:                                glyphPos);
0804:                    }
0805:
0806:                    gjis = null; // We don't need justification infos any more
0807:                    // Also we have to reset cached bounds and metrics
0808:                    this .visualBounds = null;
0809:                    this .logicalBounds = null;
0810:
0811:                    return glyphOffset; // How much our segment grown or shrunk
0812:                }
0813:            }
0814:
0815:            public static class TextRunSegmentGraphic extends TextRunSegment {
0816:                GraphicAttribute ga;
0817:                int start;
0818:                int length;
0819:                float fullAdvance;
0820:
0821:                TextRunSegmentGraphic(GraphicAttribute attr, int len, int start) {
0822:                    this .start = start;
0823:                    length = len;
0824:                    ga = attr;
0825:                    metrics = new BasicMetrics(ga);
0826:                    fullAdvance = ga.getAdvance() * length;
0827:                }
0828:
0829:                @Override
0830:                public Object clone() {
0831:                    return new TextRunSegmentGraphic(ga, length, start);
0832:                }
0833:
0834:                // Renders this text run segment
0835:                @Override
0836:                void draw(Graphics2D g2d, float xOffset, float yOffset) {
0837:                    if (decoration != null) {
0838:                        TextDecorator.prepareGraphics(this , g2d, xOffset,
0839:                                yOffset);
0840:                    }
0841:
0842:                    float xPos = x + xOffset;
0843:                    float yPos = y + yOffset;
0844:
0845:                    for (int i = 0; i < length; i++) {
0846:                        ga.draw(g2d, xPos, yPos);
0847:                        xPos += ga.getAdvance();
0848:                    }
0849:
0850:                    if (decoration != null) {
0851:                        TextDecorator.drawTextDecorations(this , g2d, xOffset,
0852:                                yOffset);
0853:                        TextDecorator.restoreGraphics(decoration, g2d);
0854:                    }
0855:                }
0856:
0857:                // Returns visual bounds of this segment
0858:                @Override
0859:                Rectangle2D getVisualBounds() {
0860:                    if (visualBounds == null) {
0861:                        Rectangle2D bounds = ga.getBounds();
0862:
0863:                        // First and last chars can be out of logical bounds, so we calculate
0864:                        // (bounds.getWidth() - ga.getAdvance()) which is exactly the difference
0865:                        bounds.setRect(bounds.getMinX() + x, bounds.getMinY()
0866:                                + y, bounds.getWidth() - ga.getAdvance()
0867:                                + getAdvance(), bounds.getHeight());
0868:                        visualBounds = TextDecorator.extendVisualBounds(this ,
0869:                                bounds, decoration);
0870:                    }
0871:
0872:                    return (Rectangle2D) visualBounds.clone();
0873:                }
0874:
0875:                @Override
0876:                Rectangle2D getLogicalBounds() {
0877:                    if (logicalBounds == null) {
0878:                        logicalBounds = new Rectangle2D.Float(x, y
0879:                                - metrics.ascent, getAdvance(), metrics.ascent
0880:                                + metrics.descent);
0881:                    }
0882:
0883:                    return (Rectangle2D) logicalBounds.clone();
0884:                }
0885:
0886:                @Override
0887:                float getAdvance() {
0888:                    return fullAdvance;
0889:                }
0890:
0891:                @Override
0892:                float getAdvanceDelta(int start, int end) {
0893:                    return ga.getAdvance() * (end - start);
0894:                }
0895:
0896:                @Override
0897:                int getCharIndexFromAdvance(float advance, int start) {
0898:                    start -= this .start;
0899:
0900:                    if (start < 0) {
0901:                        start = 0;
0902:                    }
0903:
0904:                    int charOffset = (int) (advance / ga.getAdvance());
0905:
0906:                    if (charOffset + start > length) {
0907:                        return length + this .start;
0908:                    }
0909:                    return charOffset + start + this .start;
0910:                }
0911:
0912:                @Override
0913:                int getStart() {
0914:                    return start;
0915:                }
0916:
0917:                @Override
0918:                int getEnd() {
0919:                    return start + length;
0920:                }
0921:
0922:                @Override
0923:                int getLength() {
0924:                    return length;
0925:                }
0926:
0927:                @Override
0928:                Shape getCharsBlackBoxBounds(int start, int limit) {
0929:                    start -= this .start;
0930:                    limit -= this .start;
0931:
0932:                    if (limit > length) {
0933:                        limit = length;
0934:                    }
0935:
0936:                    Rectangle2D charBounds = ga.getBounds();
0937:                    charBounds.setRect(charBounds.getX() + ga.getAdvance()
0938:                            * start + x, charBounds.getY() + y, charBounds
0939:                            .getWidth()
0940:                            + ga.getAdvance() * (limit - start), charBounds
0941:                            .getHeight());
0942:
0943:                    return charBounds;
0944:                }
0945:
0946:                @Override
0947:                float getCharPosition(int index) {
0948:                    index -= start;
0949:                    if (index > length) {
0950:                        index = length;
0951:                    }
0952:
0953:                    return ga.getAdvance() * index + x;
0954:                }
0955:
0956:                @Override
0957:                float getCharAdvance(int index) {
0958:                    return ga.getAdvance();
0959:                }
0960:
0961:                @Override
0962:                Shape getOutline() {
0963:                    AffineTransform t = AffineTransform.getTranslateInstance(x,
0964:                            y);
0965:                    return t
0966:                            .createTransformedShape(TextDecorator
0967:                                    .extendOutline(this , getVisualBounds(),
0968:                                            decoration));
0969:                }
0970:
0971:                @Override
0972:                boolean charHasZeroAdvance(int index) {
0973:                    return false;
0974:                }
0975:
0976:                @Override
0977:                TextHitInfo hitTest(float hitX, float hitY) {
0978:                    hitX -= x;
0979:
0980:                    float tmp = hitX / ga.getAdvance();
0981:                    int hitIndex = Math.round(tmp);
0982:
0983:                    if (tmp > hitIndex) {
0984:                        return TextHitInfo.leading(hitIndex + this .start);
0985:                    }
0986:                    return TextHitInfo.trailing(hitIndex + this .start);
0987:                }
0988:
0989:                @Override
0990:                void updateJustificationInfo(
0991:                        TextRunBreaker.JustificationInfo jInfo) {
0992:                    // Do nothing
0993:                }
0994:
0995:                @Override
0996:                float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
0997:                    // Do nothing
0998:                    return 0;
0999:                }
1000:            }
1001:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.