Program: 194421
Project: 194421
Buggy source:
/** 
 * @hide
 */
public void drawText(Canvas canvas,int firstLine,int lastLine){
  int previousLineBottom=getLineTop(firstLine);
  int previousLineEnd=getLineStart(firstLine);
  ParagraphStyle[] spans=NO_PARA_SPANS;
  int spanEnd=0;
  TextPaint paint=mPaint;
  CharSequence buf=mText;
  Alignment paraAlign=mAlignment;
  TabStops tabStops=null;
  boolean tabStopsIsInitialized=false;
  TextLine tl=TextLine.obtain();
  for (int lineNum=firstLine; lineNum <= lastLine; lineNum++) {
    int start=previousLineEnd;
    previousLineEnd=getLineStart(lineNum + 1);
    int end=getLineVisibleEnd(lineNum,start,previousLineEnd);
    int ltop=previousLineBottom;
    int lbottom=getLineTop(lineNum + 1);
    previousLineBottom=lbottom;
    int lbaseline=lbottom - getLineDescent(lineNum);
    int dir=getParagraphDirection(lineNum);
    int left=0;
    int right=mWidth;
    if (mSpannedText) {
      Spanned sp=(Spanned)buf;
      int textLength=buf.length();
      boolean isFirstParaLine=(start == 0 || buf.charAt(start - 1) == '\n');
      if (start >= spanEnd && (lineNum == firstLine || isFirstParaLine)) {
        spanEnd=sp.nextSpanTransition(start,textLength,ParagraphStyle.class);
        spans=getParagraphSpans(sp,start,spanEnd,ParagraphStyle.class);
        paraAlign=mAlignment;
        for (int n=spans.length - 1; n >= 0; n--) {
          if (spans[n] instanceof AlignmentSpan) {
            paraAlign=((AlignmentSpan)spans[n]).getAlignment();
            break;
          }
        }
        tabStopsIsInitialized=false;
      }
      final int length=spans.length;
      boolean useFirstLineMargin=isFirstParaLine;
      for (int n=0; n < length; n++) {
        if (spans[n] instanceof LeadingMarginSpan2) {
          int count=((LeadingMarginSpan2)spans[n]).getLeadingMarginLineCount();
          int startLine=getLineForOffset(sp.getSpanStart(spans[n]));
          if (lineNum < startLine + count) {
            useFirstLineMargin=true;
            break;
          }
        }
      }
      for (int n=0; n < length; n++) {
        if (spans[n] instanceof LeadingMarginSpan) {
          LeadingMarginSpan margin=(LeadingMarginSpan)spans[n];
          if (dir == DIR_RIGHT_TO_LEFT) {
            margin.drawLeadingMargin(canvas,paint,right,dir,ltop,lbaseline,lbottom,buf,start,end,isFirstParaLine,this);
            right-=margin.getLeadingMargin(useFirstLineMargin);
          }
 else {
            margin.drawLeadingMargin(canvas,paint,left,dir,ltop,lbaseline,lbottom,buf,start,end,isFirstParaLine,this);
            left+=margin.getLeadingMargin(useFirstLineMargin);
          }
        }
      }
    }
    boolean hasTabOrEmoji=getLineContainsTab(lineNum);
    if (hasTabOrEmoji && !tabStopsIsInitialized) {
      if (tabStops == null) {
        tabStops=new TabStops(TAB_INCREMENT,spans);
      }
 else {
        tabStops.reset(TAB_INCREMENT,spans);
      }
      tabStopsIsInitialized=true;
    }
    Alignment align=paraAlign;
    if (align == Alignment.ALIGN_LEFT) {
      align=(dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
    }
 else     if (align == Alignment.ALIGN_RIGHT) {
      align=(dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_OPPOSITE : Alignment.ALIGN_NORMAL;
    }
    int x;
    if (align == Alignment.ALIGN_NORMAL) {
      if (dir == DIR_LEFT_TO_RIGHT) {
        x=left;
      }
 else {
        x=right;
      }
    }
 else {
      int max=(int)getLineExtent(lineNum,tabStops,false);
      if (align == Alignment.ALIGN_OPPOSITE) {
        if (dir == DIR_LEFT_TO_RIGHT) {
          x=right - max;
        }
 else {
          x=left - max;
        }
      }
 else {
        max=max & ~1;
        x=(right + left - max) >> 1;
      }
    }
    paint.setHyphenEdit(getHyphen(lineNum));
    Directions directions=getLineDirections(lineNum);
    if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) {
      canvas.drawText(buf,start,end,x,lbaseline,paint);
    }
 else {
      tl.set(paint,buf,start,end,dir,directions,hasTabOrEmoji,tabStops);
      tl.draw(canvas,x,ltop,lbaseline,lbottom);
    }
    paint.setHyphenEdit(0);
  }
  TextLine.recycle(tl);
}

Fixed version (ground truth):
/** 
 * @hide
 */
public void drawText(Canvas canvas,int firstLine,int lastLine){
  int previousLineBottom=getLineTop(firstLine);
  int previousLineEnd=getLineStart(firstLine);
  ParagraphStyle[] spans=NO_PARA_SPANS;
  int spanEnd=0;
  TextPaint paint=mPaint;
  CharSequence buf=mText;
  Alignment paraAlign=mAlignment;
  TabStops tabStops=null;
  boolean tabStopsIsInitialized=false;
  TextLine tl=TextLine.obtain();
  for (int lineNum=firstLine; lineNum <= lastLine; lineNum++) {
    int start=previousLineEnd;
    previousLineEnd=getLineStart(lineNum + 1);
    int end=getLineVisibleEnd(lineNum,start,previousLineEnd);
    int ltop=previousLineBottom;
    int lbottom=getLineTop(lineNum + 1);
    previousLineBottom=lbottom;
    int lbaseline=lbottom - getLineDescent(lineNum);
    int dir=getParagraphDirection(lineNum);
    int left=0;
    int right=mWidth;
    if (mSpannedText) {
      Spanned sp=(Spanned)buf;
      int textLength=buf.length();
      boolean isFirstParaLine=(start == 0 || buf.charAt(start - 1) == '\n');
      if (start >= spanEnd && (lineNum == firstLine || isFirstParaLine)) {
        spanEnd=sp.nextSpanTransition(start,textLength,ParagraphStyle.class);
        spans=getParagraphSpans(sp,start,spanEnd,ParagraphStyle.class);
        paraAlign=mAlignment;
        for (int n=spans.length - 1; n >= 0; n--) {
          if (spans[n] instanceof AlignmentSpan) {
            paraAlign=((AlignmentSpan)spans[n]).getAlignment();
            break;
          }
        }
        tabStopsIsInitialized=false;
      }
      final int length=spans.length;
      boolean useFirstLineMargin=isFirstParaLine;
      for (int n=0; n < length; n++) {
        if (spans[n] instanceof LeadingMarginSpan2) {
          int count=((LeadingMarginSpan2)spans[n]).getLeadingMarginLineCount();
          int startLine=getLineForOffset(sp.getSpanStart(spans[n]));
          if (lineNum < startLine + count) {
            useFirstLineMargin=true;
            break;
          }
        }
      }
      for (int n=0; n < length; n++) {
        if (spans[n] instanceof LeadingMarginSpan) {
          LeadingMarginSpan margin=(LeadingMarginSpan)spans[n];
          if (dir == DIR_RIGHT_TO_LEFT) {
            margin.drawLeadingMargin(canvas,paint,right,dir,ltop,lbaseline,lbottom,buf,start,end,isFirstParaLine,this);
            right-=margin.getLeadingMargin(useFirstLineMargin);
          }
 else {
            margin.drawLeadingMargin(canvas,paint,left,dir,ltop,lbaseline,lbottom,buf,start,end,isFirstParaLine,this);
            left+=margin.getLeadingMargin(useFirstLineMargin);
          }
        }
      }
    }
    boolean hasTabOrEmoji=getLineContainsTab(lineNum);
    if (hasTabOrEmoji && !tabStopsIsInitialized) {
      if (tabStops == null) {
        tabStops=new TabStops(TAB_INCREMENT,spans);
      }
 else {
        tabStops.reset(TAB_INCREMENT,spans);
      }
      tabStopsIsInitialized=true;
    }
    Alignment align=paraAlign;
    if (align == Alignment.ALIGN_LEFT) {
      align=(dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
    }
 else     if (align == Alignment.ALIGN_RIGHT) {
      align=(dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_OPPOSITE : Alignment.ALIGN_NORMAL;
    }
    int x;
    if (align == Alignment.ALIGN_NORMAL) {
      if (dir == DIR_LEFT_TO_RIGHT) {
        x=left + getIndentAdjust(lineNum,Alignment.ALIGN_LEFT);
      }
 else {
        x=right + getIndentAdjust(lineNum,Alignment.ALIGN_RIGHT);
      }
    }
 else {
      int max=(int)getLineExtent(lineNum,tabStops,false);
      if (align == Alignment.ALIGN_OPPOSITE) {
        if (dir == DIR_LEFT_TO_RIGHT) {
          x=right - max + getIndentAdjust(lineNum,Alignment.ALIGN_RIGHT);
        }
 else {
          x=left - max + getIndentAdjust(lineNum,Alignment.ALIGN_LEFT);
        }
      }
 else {
        max=max & ~1;
        x=((right + left - max) >> 1) + getIndentAdjust(lineNum,Alignment.ALIGN_CENTER);
      }
    }
    paint.setHyphenEdit(getHyphen(lineNum));
    Directions directions=getLineDirections(lineNum);
    if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) {
      canvas.drawText(buf,start,end,x,lbaseline,paint);
    }
 else {
      tl.set(paint,buf,start,end,dir,directions,hasTabOrEmoji,tabStops);
      tl.draw(canvas,x,ltop,lbaseline,lbottom);
    }
    paint.setHyphenEdit(0);
  }
  TextLine.recycle(tl);
}