package com.marshalchen.common.uimodule.flowtextview.helpers; import android.graphics.Typeface; import android.text.Spannable; import android.text.TextPaint; import android.text.style.StyleSpan; import android.text.style.URLSpan; import com.marshalchen.common.uimodule.flowtextview.FlowTextView; import com.marshalchen.common.uimodule.flowtextview.models.HtmlLink; import com.marshalchen.common.uimodule.flowtextview.models.HtmlObject; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; /** * Created by Dean on 24/06/2014. */ public class SpanParser { public SpanParser(FlowTextView flowTextView, PaintHelper paintHelper) { this.mFlowTextView = flowTextView; this.mPaintHelper = paintHelper; } private final PaintHelper mPaintHelper; private final FlowTextView mFlowTextView; private final ArrayList<HtmlLink> mLinks = new ArrayList<HtmlLink>(); private int mTextLength = 0; private Spannable mSpannable; private final HashMap<Integer, HtmlObject> sorterMap = new HashMap<Integer, HtmlObject>(); public float parseSpans(ArrayList<HtmlObject> objects, Object[] spans, int lineStart, int lineEnd, float baseXOffset){ sorterMap.clear(); int charFlagSize = lineEnd - lineStart; boolean[] charFlags = new boolean[charFlagSize]; String tempString; int spanStart; int spanEnd; int charCounter; for (Object span : spans) { spanStart = mSpannable.getSpanStart(span); spanEnd = mSpannable.getSpanEnd(span); if(spanStart <lineStart) spanStart = lineStart; if(spanEnd >lineEnd) spanEnd = lineEnd; for(charCounter = spanStart; charCounter < spanEnd; charCounter++){ // mark these characters as rendered int charFlagIndex = charCounter - lineStart; charFlags[charFlagIndex] = true; } tempString = extractText(spanStart, spanEnd); sorterMap.put(spanStart, parseSpan(span, tempString, spanStart, spanEnd)); } charCounter = 0; while(!isArrayFull(charFlags)){ while(true){ if(charCounter >= charFlagSize) break; if(charFlags[charCounter]==true){ charCounter++; continue; } int temp1 = charCounter; while(true){ if(charCounter > charFlagSize) break; if(charCounter < charFlagSize){ if(charFlags[charCounter] == false){ charFlags[charCounter] = true;// mark as filled charCounter++; continue; } } int temp2 = charCounter; spanStart = lineStart + temp1; spanEnd = lineStart + temp2; tempString = extractText(spanStart, spanEnd); sorterMap.put(spanStart, parseSpan(null, tempString, spanStart, spanEnd)); break; } } } Object[] sorterKeys = sorterMap.keySet().toArray(); Arrays.sort(sorterKeys); float thisXoffset = baseXOffset; for(charCounter =0; charCounter < sorterKeys.length; charCounter++){ HtmlObject thisObj = sorterMap.get(sorterKeys[charCounter]); thisObj.xOffset = thisXoffset; thisXoffset += thisObj.paint.measureText(thisObj.content); objects.add(thisObj); } return (thisXoffset - baseXOffset); } private HtmlObject parseSpan(Object span, String content, int start, int end){ if(span instanceof URLSpan){ return getHtmlLink((URLSpan) span, content, start, end, 0); }else if(span instanceof StyleSpan){ return getStyledObject((StyleSpan) span, content, start, end, 0); }else{ return getHtmlObject(content, start, end, 0); } } private HtmlObject getStyledObject(StyleSpan span, String content, int start, int end, float thisXOffset){ TextPaint paint = mPaintHelper.getPaintFromHeap(); paint.setTypeface(Typeface.defaultFromStyle(span.getStyle())); paint.setTextSize(mFlowTextView.getTextsize()); paint.setColor(mFlowTextView.getColor()); span.updateDrawState(paint); span.updateMeasureState(paint); HtmlObject obj = new HtmlObject(content, start, end, thisXOffset, paint); obj.recycle = true; return obj; } private HtmlObject getHtmlObject(String content, int start, int end, float thisXOffset){ return new HtmlObject(content, start, end, thisXOffset, mFlowTextView.getTextPaint()); } public void reset(){ mLinks.clear(); } private HtmlLink getHtmlLink(URLSpan span, String content, int start, int end, float thisXOffset){ HtmlLink obj = new HtmlLink(content, start, end, thisXOffset, mFlowTextView.getLinkPaint(), span.getURL()); mLinks.add(obj); return obj; } public void addLink(HtmlLink thisLink, float yOffset, float width, float height){ thisLink.yOffset = yOffset - 20; thisLink.width = width; thisLink.height = height + 20; mLinks.add(thisLink); } private String extractText(int start, int end){ if(start<0) start = 0; if(end > mTextLength-1) end = mTextLength-1; return mSpannable.subSequence(start, end).toString(); } private static boolean isArrayFull(boolean[] array){ for(int arrayIndex=0; arrayIndex<array.length; arrayIndex++){ if(array[arrayIndex] == false) return false; } return true; } // GETTERS AND SETTERS public ArrayList<HtmlLink> getLinks() { return mLinks; } public Spannable getSpannable() { return mSpannable; } public void setSpannable(Spannable mSpannable) { this.mSpannable = mSpannable; mTextLength = mSpannable.length(); } }