package com.smartandroid.sa.floatextview; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import android.graphics.Typeface; import android.text.Spannable; import android.text.TextPaint; import android.text.style.StyleSpan; import android.text.style.URLSpan; /** * 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(); } }