/** * Add a new Decoration run with the given Decoration at the * given index. */ private void addDecoration(Decoration d, int index) { if (decorations != null) { decorationStarts = addToVector(d, index, decorations, decorationStarts); } else if (decoration == null) { decoration = d; } else { if (!decoration.equals(d)) { decorations = new Vector<Decoration>(INITIAL_SIZE); decorations.addElement(decoration); decorations.addElement(d); decorationStarts = new int[INITIAL_SIZE]; decorationStarts[0] = 0; decorationStarts[1] = index; } } }
/** * Add a new Decoration run with the given Decoration at the * given index. */ private void addDecoration(Decoration d, int index) { if (decorations != null) { decorationStarts = addToVector(d, index, decorations, decorationStarts); } else if (decoration == null) { decoration = d; } else { if (!decoration.equals(d)) { decorations = new Vector(INITIAL_SIZE); decorations.addElement(decoration); decorations.addElement(d); decorationStarts = new int[INITIAL_SIZE]; decorationStarts[0] = 0; decorationStarts[1] = index; } } }
/** * Create a new StyledParagraph over the given styled text. * @param aci an iterator over the text * @param chars the characters extracted from aci */ public StyledParagraph(AttributedCharacterIterator aci, char[] chars) { int start = aci.getBeginIndex(); int end = aci.getEndIndex(); length = end - start; int index = start; aci.first(); do { final int nextRunStart = aci.getRunLimit(); final int localIndex = index-start; Map<? extends Attribute, ?> attributes = aci.getAttributes(); attributes = addInputMethodAttrs(attributes); Decoration d = Decoration.getDecoration(attributes); addDecoration(d, localIndex); Object f = getGraphicOrFont(attributes); if (f == null) { addFonts(chars, attributes, localIndex, nextRunStart-start); } else { addFont(f, localIndex); } aci.setIndex(nextRunStart); index = nextRunStart; } while (index < end); // Add extra entries to starts arrays with the length // of the paragraph. 'this' is used as a dummy value // in the Vector. if (decorations != null) { decorationStarts = addToVector(this, length, decorations, decorationStarts); } if (fonts != null) { fontStarts = addToVector(this, length, fonts, fontStarts); } }
/** * Return a StyledParagraph reflecting the insertion of a single character * into the text. This method will attempt to reuse the given paragraph, * but may create a new paragraph. * @param aci an iterator over the text. The text should be the same as the * text used to create (or most recently update) oldParagraph, with * the exception of inserting a single character at insertPos. * @param chars the characters in aci * @param insertPos the index of the new character in aci * @param oldParagraph a StyledParagraph for the text in aci before the * insertion */ public static StyledParagraph insertChar(AttributedCharacterIterator aci, char[] chars, int insertPos, StyledParagraph oldParagraph) { // If the styles at insertPos match those at insertPos-1, // oldParagraph will be reused. Otherwise we create a new // paragraph. char ch = aci.setIndex(insertPos); int relativePos = Math.max(insertPos - aci.getBeginIndex() - 1, 0); Map<? extends Attribute, ?> attributes = addInputMethodAttrs(aci.getAttributes()); Decoration d = Decoration.getDecoration(attributes); if (!oldParagraph.getDecorationAt(relativePos).equals(d)) { return new StyledParagraph(aci, chars); } Object f = getGraphicOrFont(attributes); if (f == null) { FontResolver resolver = FontResolver.getInstance(); int fontIndex = resolver.getFontIndex(ch); f = resolver.getFont(fontIndex, attributes); } if (!oldParagraph.getFontOrGraphicAt(relativePos).equals(f)) { return new StyledParagraph(aci, chars); } // insert into existing paragraph oldParagraph.length += 1; if (oldParagraph.decorations != null) { insertInto(relativePos, oldParagraph.decorationStarts, oldParagraph.decorations.size()); } if (oldParagraph.fonts != null) { insertInto(relativePos, oldParagraph.fontStarts, oldParagraph.fonts.size()); } return oldParagraph; }
/** * Return the Decoration in effect at the given index. * @param index a valid index in the paragraph * @return the Decoration at index. */ public Decoration getDecorationAt(int index) { if (index < 0 || index >= length) { throw new IllegalArgumentException("index out of range"); } if (decorations == null) { return decoration; } int run = findRunContaining(index, decorationStarts); return decorations.elementAt(run); }
/** * Return the Decoration in effect at the given index. * @param index a valid index in the paragraph * @return the Decoration at index. */ public Decoration getDecorationAt(int index) { if (index < 0 || index >= length) { throw new IllegalArgumentException("index out of range"); } if (decorations == null) { return decoration; } int run = findRunContaining(index, decorationStarts); return (Decoration) decorations.elementAt(run); }
/** * Returns an array in logical order of the TextLineComponents on * the text in the given range, with the given attributes. */ public static TextLineComponent[] createComponentsOnRun(int runStart, int runLimit, char[] chars, int[] charsLtoV, byte[] levels, TextLabelFactory factory, Font font, CoreMetrics cm, FontRenderContext frc, Decoration decorator, TextLineComponent[] components, int numComponents) { int pos = runStart; do { int chunkLimit = firstVisualChunk(charsLtoV, levels, pos, runLimit); // <= displayLimit do { int startPos = pos; int lmCount; if (cm == null) { LineMetrics lineMetrics = font.getLineMetrics(chars, startPos, chunkLimit, frc); cm = CoreMetrics.get(lineMetrics); lmCount = lineMetrics.getNumChars(); } else { lmCount = (chunkLimit-startPos); } TextLineComponent nextComponent = factory.createExtended(font, cm, decorator, startPos, startPos + lmCount); ++numComponents; if (numComponents >= components.length) { components = expandArray(components); } components[numComponents-1] = nextComponent; pos += lmCount; } while (pos < chunkLimit); } while (pos < runLimit); return components; }
/** * Returns an array (in logical order) of the TextLineComponents representing * the text. The components are both logically and visually contiguous. */ public static TextLineComponent[] getComponents(StyledParagraph styledParagraph, char[] chars, int textStart, int textLimit, int[] charsLtoV, byte[] levels, TextLabelFactory factory) { FontRenderContext frc = factory.getFontRenderContext(); int numComponents = 0; TextLineComponent[] tempComponents = new TextLineComponent[1]; int pos = textStart; do { int runLimit = Math.min(styledParagraph.getRunLimit(pos), textLimit); Decoration decorator = styledParagraph.getDecorationAt(pos); Object graphicOrFont = styledParagraph.getFontOrGraphicAt(pos); if (graphicOrFont instanceof GraphicAttribute) { // AffineTransform baseRot = styledParagraph.getBaselineRotationAt(pos); // !!! For now, let's assign runs of text with both fonts and graphic attributes // a null rotation (e.g. the baseline rotation goes away when a graphic // is applied. AffineTransform baseRot = null; GraphicAttribute graphicAttribute = (GraphicAttribute) graphicOrFont; do { int chunkLimit = firstVisualChunk(charsLtoV, levels, pos, runLimit); GraphicComponent nextGraphic = new GraphicComponent(graphicAttribute, decorator, charsLtoV, levels, pos, chunkLimit, baseRot); pos = chunkLimit; ++numComponents; if (numComponents >= tempComponents.length) { tempComponents = expandArray(tempComponents); } tempComponents[numComponents-1] = nextGraphic; } while(pos < runLimit); } else { Font font = (Font) graphicOrFont; tempComponents = createComponentsOnRun(pos, runLimit, chars, charsLtoV, levels, factory, font, null, frc, decorator, tempComponents, numComponents); pos = runLimit; numComponents = tempComponents.length; while (tempComponents[numComponents-1] == null) { numComponents -= 1; } } } while (pos < textLimit); TextLineComponent[] components; if (tempComponents.length == numComponents) { components = tempComponents; } else { components = new TextLineComponent[numComponents]; System.arraycopy(tempComponents, 0, components, 0, numComponents); } return components; }