private Rectangle2D.Double appendParagraph(@Nullable Path2D.Double shape,AttributedCharacterIterator styledText,float verticalPos,float maxVerticalPos,float leftMargin,float rightMargin,float[] tabStops,int tabCount){
  Rectangle2D.Double paragraphBounds=new Rectangle2D.Double(leftMargin,verticalPos,0,0);
  int[] tabLocations=new int[tabCount + 1];
  int i=0;
  for (char c=styledText.first(); c != styledText.DONE; c=styledText.next()) {
    if (c == '\t') {
      tabLocations[i++]=styledText.getIndex();
    }
  }
  tabLocations[tabCount]=styledText.getEndIndex() - 1;
  LineBreakMeasurer measurer=new LineBreakMeasurer(styledText,getFontRenderContext());
  int currentTab=0;
  while (measurer.getPosition() < styledText.getEndIndex()) {
    boolean lineContainsText=false;
    boolean lineComplete=false;
    float maxAscent=0, maxDescent=0;
    float horizontalPos=leftMargin;
    LinkedList<TextLayout> layouts=new LinkedList<TextLayout>();
    LinkedList<Float> penPositions=new LinkedList<Float>();
    while (!lineComplete) {
      float wrappingWidth=rightMargin - horizontalPos;
      TextLayout layout=null;
      layout=measurer.nextLayout(wrappingWidth,tabLocations[currentTab] + 1,lineContainsText);
      if (layout != null) {
        layouts.add(layout);
        penPositions.add(horizontalPos);
        horizontalPos+=layout.getAdvance();
        maxAscent=Math.max(maxAscent,layout.getAscent());
        maxDescent=Math.max(maxDescent,layout.getDescent() + layout.getLeading());
      }
 else {
        lineComplete=true;
      }
      lineContainsText=true;
      if (measurer.getPosition() == tabLocations[currentTab] + 1) {
        currentTab++;
      }
      if (measurer.getPosition() == styledText.getEndIndex()) {
        lineComplete=true;
      }
 else       if (tabStops.length == 0 || horizontalPos >= tabStops[tabStops.length - 1]) {
        lineComplete=true;
      }
      if (!lineComplete) {
        int j;
        for (j=0; horizontalPos >= tabStops[j]; j++) {
        }
        horizontalPos=tabStops[j];
      }
    }
    verticalPos+=maxAscent;
    if (verticalPos > maxVerticalPos) {
      break;
    }
    Iterator<TextLayout> layoutEnum=layouts.iterator();
    Iterator<Float> positionEnum=penPositions.iterator();
    while (layoutEnum.hasNext()) {
      TextLayout nextLayout=layoutEnum.next();
      float nextPosition=positionEnum.next();
      AffineTransform tx=new AffineTransform();
      tx.translate(nextPosition,verticalPos);
      if (shape != null) {
        Shape outline=nextLayout.getOutline(tx);
        shape.append(outline,false);
      }
      Rectangle2D layoutBounds=nextLayout.getBounds();
      paragraphBounds.add(new Rectangle2D.Double(layoutBounds.getX() + nextPosition,layoutBounds.getY() + verticalPos,layoutBounds.getWidth(),layoutBounds.getHeight()));
    }
    verticalPos+=maxDescent;
  }
  return paragraphBounds;
}

private Rectangle2D . Double appendParagraph ( @ Nullable Path2D . Double shape , AttributedCharacterIterator styledText , float verticalPos , float maxVerticalPos , float leftMargin , float rightMargin , float [ ] tabStops , int tabCount ) { Rectangle2D . Double paragraphBounds = new Rectangle2D . Double ( leftMargin , verticalPos , 0 , 0 ) ; int [ ] tabLocations = new int [ tabCount + 1 ] ; int i = 0 ; for ( char c = styledText . first ( ) ; c != styledText . DONE ; c = styledText . next ( ) ) { if ( c == '\t' ) { tabLocations [ i ++ ] = styledText . getIndex ( ) ; } } tabLocations [ tabCount ] = styledText . getEndIndex ( ) - 1 ; LineBreakMeasurer measurer = new LineBreakMeasurer ( styledText , getFontRenderContext ( ) ) ; int currentTab = 0 ; while ( measurer . getPosition ( ) < styledText . getEndIndex ( ) ) { boolean lineContainsText = false ; boolean lineComplete = false ; float maxAscent = 0 , maxDescent = 0 ; float horizontalPos = leftMargin ; LinkedList < TextLayout > layouts = new LinkedList < TextLayout > ( ) ; LinkedList < Float > penPositions = new LinkedList < Float > ( ) ; while ( ! lineComplete ) { float wrappingWidth = rightMargin - horizontalPos ; TextLayout layout = null ; layout = measurer . nextLayout ( wrappingWidth , tabLocations [ currentTab ] + 1 , lineContainsText ) ; if ( layout != null ) { layouts . add ( layout ) ; penPositions . add ( horizontalPos ) ; horizontalPos += layout . getAdvance ( ) ; maxAscent = Math . max ( maxAscent , layout . getAscent ( ) ) ; maxDescent = Math . max ( maxDescent , layout . getDescent ( ) + layout . getLeading ( ) ) ; } else { lineComplete = true ; } lineContainsText = true ; if ( measurer . getPosition ( ) == tabLocations [ currentTab ] + 1 ) { currentTab ++ ; } if ( measurer . getPosition ( ) == styledText . getEndIndex ( ) ) { lineComplete = true ; } else if ( tabStops . length == 0 || horizontalPos >= tabStops [ tabStops . length - 1 ] ) { lineComplete = true ; } if ( ! lineComplete ) { int j ; for ( j = 0 ; horizontalPos >= tabStops [ j ] ; j ++ ) { } horizontalPos = tabStops [ j ] ; } } verticalPos += maxAscent ; if ( verticalPos > maxVerticalPos ) { break ; } Iterator < TextLayout > layoutEnum = layouts . iterator ( ) ; Iterator < Float > positionEnum = penPositions . iterator ( ) ; while ( layoutEnum . hasNext ( ) ) { TextLayout nextLayout = layoutEnum . next ( ) ; float nextPosition = positionEnum . next ( ) ; AffineTransform tx = new AffineTransform ( ) ; tx . translate ( nextPosition , verticalPos ) ; if ( shape != null ) { Shape outline = nextLayout . getOutline ( tx ) ; shape . append ( outline , false ) ; } Rectangle2D layoutBounds = nextLayout . getBounds ( ) ; paragraphBounds . add ( new Rectangle2D . Double ( layoutBounds . getX ( ) + nextPosition , layoutBounds . getY ( ) + verticalPos , layoutBounds . getWidth ( ) , layoutBounds . getHeight ( ) ) ) ; } verticalPos += maxDescent ; } return paragraphBounds ; }
appends a paragraph of text at the specified y location and returns the bounds of the paragraph .
