Search in sources :

Example 36 with CharacterStyle

use of android.text.style.CharacterStyle in project android_frameworks_base by AOSPA.

the class TextLine method handleRun.

/**
     * Utility function for handling a unidirectional run.  The run must not
     * contain tabs but can contain styles.
     *
     *
     * @param start the line-relative start of the run
     * @param measureLimit the offset to measure to, between start and limit inclusive
     * @param limit the limit of the run
     * @param runIsRtl true if the run is right-to-left
     * @param c the canvas, can be null
     * @param x the end of the run closest to the leading margin
     * @param top the top of the line
     * @param y the baseline
     * @param bottom the bottom of the line
     * @param fmi receives metrics information, can be null
     * @param needWidth true if the width is required
     * @return the signed width of the run based on the run direction; only
     * valid if needWidth is true
     */
private float handleRun(int start, int measureLimit, int limit, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth) {
    // Case of an empty line, make sure we update fmi according to mPaint
    if (start == measureLimit) {
        TextPaint wp = mWorkPaint;
        wp.set(mPaint);
        if (fmi != null) {
            expandMetricsFromPaint(fmi, wp);
        }
        return 0f;
    }
    if (mSpanned == null) {
        TextPaint wp = mWorkPaint;
        wp.set(mPaint);
        final int mlimit = measureLimit;
        return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top, y, bottom, fmi, needWidth || mlimit < measureLimit, mlimit);
    }
    mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
    mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);
    // Shaping needs to take into account context up to metric boundaries,
    // but rendering needs to take into account character style boundaries.
    // So we iterate through metric runs to get metric bounds,
    // then within each metric run iterate through character style runs
    // for the run bounds.
    final float originalX = x;
    for (int i = start, inext; i < measureLimit; i = inext) {
        TextPaint wp = mWorkPaint;
        wp.set(mPaint);
        inext = mMetricAffectingSpanSpanSet.getNextTransition(mStart + i, mStart + limit) - mStart;
        int mlimit = Math.min(inext, measureLimit);
        ReplacementSpan replacement = null;
        for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
            // empty by construction. This special case in getSpans() explains the >= & <= tests
            if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) || (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i))
                continue;
            MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
            if (span instanceof ReplacementSpan) {
                replacement = (ReplacementSpan) span;
            } else {
                // We might have a replacement that uses the draw
                // state, otherwise measure state would suffice.
                span.updateDrawState(wp);
            }
        }
        if (replacement != null) {
            x += handleReplacement(replacement, wp, i, mlimit, runIsRtl, c, x, top, y, bottom, fmi, needWidth || mlimit < measureLimit);
            continue;
        }
        for (int j = i, jnext; j < mlimit; j = jnext) {
            jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) - mStart;
            int offset = Math.min(jnext, mlimit);
            wp.set(mPaint);
            for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
                // Intentionally using >= and <= as explained above
                if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + offset) || (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j))
                    continue;
                CharacterStyle span = mCharacterStyleSpanSet.spans[k];
                span.updateDrawState(wp);
            }
            // Only draw hyphen on last run in line
            if (jnext < mLen) {
                wp.setHyphenEdit(0);
            }
            x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || jnext < measureLimit, offset);
        }
    }
    return x - originalX;
}
Also used : ReplacementSpan(android.text.style.ReplacementSpan) Paint(android.graphics.Paint) MetricAffectingSpan(android.text.style.MetricAffectingSpan) CharacterStyle(android.text.style.CharacterStyle)

Example 37 with CharacterStyle

use of android.text.style.CharacterStyle in project android_frameworks_base by AOSPA.

the class TextView method spanChange.

/**
     * Not private so it can be called from an inner class without going
     * through a thunk.
     */
void spanChange(Spanned buf, Object what, int oldStart, int newStart, int oldEnd, int newEnd) {
    // XXX Make the start and end move together if this ends up
    // spending too much time invalidating.
    boolean selChanged = false;
    int newSelStart = -1, newSelEnd = -1;
    final Editor.InputMethodState ims = mEditor == null ? null : mEditor.mInputMethodState;
    if (what == Selection.SELECTION_END) {
        selChanged = true;
        newSelEnd = newStart;
        if (oldStart >= 0 || newStart >= 0) {
            invalidateCursor(Selection.getSelectionStart(buf), oldStart, newStart);
            checkForResize();
            registerForPreDraw();
            if (mEditor != null)
                mEditor.makeBlink();
        }
    }
    if (what == Selection.SELECTION_START) {
        selChanged = true;
        newSelStart = newStart;
        if (oldStart >= 0 || newStart >= 0) {
            int end = Selection.getSelectionEnd(buf);
            invalidateCursor(end, oldStart, newStart);
        }
    }
    if (selChanged) {
        mHighlightPathBogus = true;
        if (mEditor != null && !isFocused())
            mEditor.mSelectionMoved = true;
        if ((buf.getSpanFlags(what) & Spanned.SPAN_INTERMEDIATE) == 0) {
            if (newSelStart < 0) {
                newSelStart = Selection.getSelectionStart(buf);
            }
            if (newSelEnd < 0) {
                newSelEnd = Selection.getSelectionEnd(buf);
            }
            if (mEditor != null) {
                mEditor.refreshTextActionMode();
                if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
                    // User generated selection has been removed.
                    setHasTransientState(false);
                }
            }
            onSelectionChanged(newSelStart, newSelEnd);
        }
    }
    if (what instanceof UpdateAppearance || what instanceof ParagraphStyle || what instanceof CharacterStyle) {
        if (ims == null || ims.mBatchEditNesting == 0) {
            invalidate();
            mHighlightPathBogus = true;
            checkForResize();
        } else {
            ims.mContentChanged = true;
        }
        if (mEditor != null) {
            if (oldStart >= 0)
                mEditor.invalidateTextDisplayList(mLayout, oldStart, oldEnd);
            if (newStart >= 0)
                mEditor.invalidateTextDisplayList(mLayout, newStart, newEnd);
            mEditor.invalidateHandlesAndActionMode();
        }
    }
    if (MetaKeyKeyListener.isMetaTracker(buf, what)) {
        mHighlightPathBogus = true;
        if (ims != null && MetaKeyKeyListener.isSelectingMetaTracker(buf, what)) {
            ims.mSelectionModeChanged = true;
        }
        if (Selection.getSelectionStart(buf) >= 0) {
            if (ims == null || ims.mBatchEditNesting == 0) {
                invalidateCursor();
            } else {
                ims.mCursorChanged = true;
            }
        }
    }
    if (what instanceof ParcelableSpan) {
        // the current extract editor would be interested in it.
        if (ims != null && ims.mExtractedTextRequest != null) {
            if (ims.mBatchEditNesting != 0) {
                if (oldStart >= 0) {
                    if (ims.mChangedStart > oldStart) {
                        ims.mChangedStart = oldStart;
                    }
                    if (ims.mChangedStart > oldEnd) {
                        ims.mChangedStart = oldEnd;
                    }
                }
                if (newStart >= 0) {
                    if (ims.mChangedStart > newStart) {
                        ims.mChangedStart = newStart;
                    }
                    if (ims.mChangedStart > newEnd) {
                        ims.mChangedStart = newEnd;
                    }
                }
            } else {
                if (DEBUG_EXTRACT)
                    Log.v(LOG_TAG, "Span change outside of batch: " + oldStart + "-" + oldEnd + "," + newStart + "-" + newEnd + " " + what);
                ims.mContentChanged = true;
            }
        }
    }
    if (mEditor != null && mEditor.mSpellChecker != null && newStart < 0 && what instanceof SpellCheckSpan) {
        mEditor.mSpellChecker.onSpellCheckSpanRemoved((SpellCheckSpan) what);
    }
}
Also used : UpdateAppearance(android.text.style.UpdateAppearance) SpellCheckSpan(android.text.style.SpellCheckSpan) ParagraphStyle(android.text.style.ParagraphStyle) ParcelableSpan(android.text.ParcelableSpan) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) CharacterStyle(android.text.style.CharacterStyle)

Example 38 with CharacterStyle

use of android.text.style.CharacterStyle in project android_frameworks_base by AOSPA.

the class Clock method getSmallTime.

private final CharSequence getSmallTime() {
    Context context = getContext();
    boolean is24 = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser());
    LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
    final char MAGIC1 = '';
    final char MAGIC2 = '';
    SimpleDateFormat sdf;
    String format = mShowSeconds ? is24 ? d.timeFormat_Hms : d.timeFormat_hms : is24 ? d.timeFormat_Hm : d.timeFormat_hm;
    if (!format.equals(mClockFormatString)) {
        mContentDescriptionFormat = new SimpleDateFormat(format);
        /*
             * Search for an unquoted "a" in the format string, so we can
             * add dummy characters around it to let us find it again after
             * formatting and change its size.
             */
        if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
            int a = -1;
            boolean quoted = false;
            for (int i = 0; i < format.length(); i++) {
                char c = format.charAt(i);
                if (c == '\'') {
                    quoted = !quoted;
                }
                if (!quoted && c == 'a') {
                    a = i;
                    break;
                }
            }
            if (a >= 0) {
                // Move a back so any whitespace before AM/PM is also in the alternate size.
                final int b = a;
                while (a > 0 && Character.isWhitespace(format.charAt(a - 1))) {
                    a--;
                }
                format = format.substring(0, a) + MAGIC1 + format.substring(a, b) + "a" + MAGIC2 + format.substring(b + 1);
            }
        }
        mClockFormat = sdf = new SimpleDateFormat(format);
        mClockFormatString = format;
    } else {
        sdf = mClockFormat;
    }
    String result = sdf.format(mCalendar.getTime());
    if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
        int magic1 = result.indexOf(MAGIC1);
        int magic2 = result.indexOf(MAGIC2);
        if (magic1 >= 0 && magic2 > magic1) {
            SpannableStringBuilder formatted = new SpannableStringBuilder(result);
            if (mAmPmStyle == AM_PM_STYLE_GONE) {
                formatted.delete(magic1, magic2 + 1);
            } else {
                if (mAmPmStyle == AM_PM_STYLE_SMALL) {
                    CharacterStyle style = new RelativeSizeSpan(0.7f);
                    formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                }
                formatted.delete(magic2, magic2 + 1);
                formatted.delete(magic1, magic1 + 1);
            }
            return formatted;
        }
    }
    return result;
}
Also used : Context(android.content.Context) LocaleData(libcore.icu.LocaleData) RelativeSizeSpan(android.text.style.RelativeSizeSpan) SimpleDateFormat(java.text.SimpleDateFormat) SpannableStringBuilder(android.text.SpannableStringBuilder) CharacterStyle(android.text.style.CharacterStyle)

Example 39 with CharacterStyle

use of android.text.style.CharacterStyle in project android_frameworks_base by AOSPA.

the class HtmlToSpannedConverter method withinParagraph.

private static void withinParagraph(StringBuilder out, Spanned text, int start, int end) {
    int next;
    for (int i = start; i < end; i = next) {
        next = text.nextSpanTransition(i, end, CharacterStyle.class);
        CharacterStyle[] style = text.getSpans(i, next, CharacterStyle.class);
        for (int j = 0; j < style.length; j++) {
            if (style[j] instanceof StyleSpan) {
                int s = ((StyleSpan) style[j]).getStyle();
                if ((s & Typeface.BOLD) != 0) {
                    out.append("<b>");
                }
                if ((s & Typeface.ITALIC) != 0) {
                    out.append("<i>");
                }
            }
            if (style[j] instanceof TypefaceSpan) {
                String s = ((TypefaceSpan) style[j]).getFamily();
                if ("monospace".equals(s)) {
                    out.append("<tt>");
                }
            }
            if (style[j] instanceof SuperscriptSpan) {
                out.append("<sup>");
            }
            if (style[j] instanceof SubscriptSpan) {
                out.append("<sub>");
            }
            if (style[j] instanceof UnderlineSpan) {
                out.append("<u>");
            }
            if (style[j] instanceof StrikethroughSpan) {
                out.append("<span style=\"text-decoration:line-through;\">");
            }
            if (style[j] instanceof URLSpan) {
                out.append("<a href=\"");
                out.append(((URLSpan) style[j]).getURL());
                out.append("\">");
            }
            if (style[j] instanceof ImageSpan) {
                out.append("<img src=\"");
                out.append(((ImageSpan) style[j]).getSource());
                out.append("\">");
                // Don't output the dummy character underlying the image.
                i = next;
            }
            if (style[j] instanceof AbsoluteSizeSpan) {
                AbsoluteSizeSpan s = ((AbsoluteSizeSpan) style[j]);
                float sizeDip = s.getSize();
                if (!s.getDip()) {
                    Application application = ActivityThread.currentApplication();
                    sizeDip /= application.getResources().getDisplayMetrics().density;
                }
                // px in CSS is the equivalance of dip in Android
                out.append(String.format("<span style=\"font-size:%.0fpx\";>", sizeDip));
            }
            if (style[j] instanceof RelativeSizeSpan) {
                float sizeEm = ((RelativeSizeSpan) style[j]).getSizeChange();
                out.append(String.format("<span style=\"font-size:%.2fem;\">", sizeEm));
            }
            if (style[j] instanceof ForegroundColorSpan) {
                int color = ((ForegroundColorSpan) style[j]).getForegroundColor();
                out.append(String.format("<span style=\"color:#%06X;\">", 0xFFFFFF & color));
            }
            if (style[j] instanceof BackgroundColorSpan) {
                int color = ((BackgroundColorSpan) style[j]).getBackgroundColor();
                out.append(String.format("<span style=\"background-color:#%06X;\">", 0xFFFFFF & color));
            }
        }
        withinStyle(out, text, i, next);
        for (int j = style.length - 1; j >= 0; j--) {
            if (style[j] instanceof BackgroundColorSpan) {
                out.append("</span>");
            }
            if (style[j] instanceof ForegroundColorSpan) {
                out.append("</span>");
            }
            if (style[j] instanceof RelativeSizeSpan) {
                out.append("</span>");
            }
            if (style[j] instanceof AbsoluteSizeSpan) {
                out.append("</span>");
            }
            if (style[j] instanceof URLSpan) {
                out.append("</a>");
            }
            if (style[j] instanceof StrikethroughSpan) {
                out.append("</span>");
            }
            if (style[j] instanceof UnderlineSpan) {
                out.append("</u>");
            }
            if (style[j] instanceof SubscriptSpan) {
                out.append("</sub>");
            }
            if (style[j] instanceof SuperscriptSpan) {
                out.append("</sup>");
            }
            if (style[j] instanceof TypefaceSpan) {
                String s = ((TypefaceSpan) style[j]).getFamily();
                if (s.equals("monospace")) {
                    out.append("</tt>");
                }
            }
            if (style[j] instanceof StyleSpan) {
                int s = ((StyleSpan) style[j]).getStyle();
                if ((s & Typeface.BOLD) != 0) {
                    out.append("</b>");
                }
                if ((s & Typeface.ITALIC) != 0) {
                    out.append("</i>");
                }
            }
        }
    }
}
Also used : SuperscriptSpan(android.text.style.SuperscriptSpan) ForegroundColorSpan(android.text.style.ForegroundColorSpan) RelativeSizeSpan(android.text.style.RelativeSizeSpan) URLSpan(android.text.style.URLSpan) CharacterStyle(android.text.style.CharacterStyle) UnderlineSpan(android.text.style.UnderlineSpan) AbsoluteSizeSpan(android.text.style.AbsoluteSizeSpan) StyleSpan(android.text.style.StyleSpan) SubscriptSpan(android.text.style.SubscriptSpan) Application(android.app.Application) BackgroundColorSpan(android.text.style.BackgroundColorSpan) TypefaceSpan(android.text.style.TypefaceSpan) StrikethroughSpan(android.text.style.StrikethroughSpan) ImageSpan(android.text.style.ImageSpan)

Example 40 with CharacterStyle

use of android.text.style.CharacterStyle in project android_frameworks_base by ResurrectionRemix.

the class Clock method getSmallTime.

private final CharSequence getSmallTime() {
    Context context = getContext();
    boolean is24 = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser());
    LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
    final char MAGIC1 = '';
    final char MAGIC2 = '';
    SimpleDateFormat sdf;
    String format = mShowSeconds ? is24 ? d.timeFormat_Hms : d.timeFormat_hms : is24 ? d.timeFormat_Hm : d.timeFormat_hm;
    if (!format.equals(mClockFormatString)) {
        mContentDescriptionFormat = new SimpleDateFormat(format);
        /*
             * Search for an unquoted "a" in the format string, so we can
             * add dummy characters around it to let us find it again after
             * formatting and change its size.
             */
        if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
            int a = -1;
            boolean quoted = false;
            for (int i = 0; i < format.length(); i++) {
                char c = format.charAt(i);
                if (c == '\'') {
                    quoted = !quoted;
                }
                if (!quoted && c == 'a') {
                    a = i;
                    break;
                }
            }
            if (a >= 0) {
                // Move a back so any whitespace before AM/PM is also in the alternate size.
                final int b = a;
                while (a > 0 && Character.isWhitespace(format.charAt(a - 1))) {
                    a--;
                }
                format = format.substring(0, a) + MAGIC1 + format.substring(a, b) + "a" + MAGIC2 + format.substring(b + 1);
            }
        }
        mClockFormat = sdf = new SimpleDateFormat(format);
        mClockFormatString = format;
    } else {
        sdf = mClockFormat;
    }
    CharSequence dateString = null;
    String result = "";
    String timeResult = sdf.format(mCalendar.getTime());
    String dateResult = "";
    int clockDatePosition = Settings.System.getInt(getContext().getContentResolver(), Settings.System.STATUSBAR_CLOCK_DATE_POSITION, 0);
    if (mClockDateDisplay != CLOCK_DATE_DISPLAY_GONE) {
        Date now = new Date();
        String clockDateFormat = Settings.System.getString(getContext().getContentResolver(), Settings.System.STATUS_BAR_DATE_FORMAT);
        if (clockDateFormat == null || clockDateFormat.isEmpty()) {
            // Set dateString to short uppercase Weekday (Default for AOKP) if empty
            dateString = DateFormat.format("EEE", now);
        } else {
            dateString = DateFormat.format(clockDateFormat, now);
        }
        if (mClockDateStyle == CLOCK_DATE_STYLE_LOWERCASE) {
            // When Date style is small, convert date to lowercase
            dateResult = dateString.toString().toLowerCase();
        } else if (mClockDateStyle == CLOCK_DATE_STYLE_UPPERCASE) {
            dateResult = dateString.toString().toUpperCase();
        } else {
            dateResult = dateString.toString();
        }
        result = (clockDatePosition == STYLE_DATE_LEFT) ? dateResult + " " + timeResult : timeResult + " " + dateResult;
    } else {
        // No date, just show time
        result = timeResult;
    }
    SpannableStringBuilder formatted = new SpannableStringBuilder(result);
    if (mClockDateDisplay != CLOCK_DATE_DISPLAY_NORMAL) {
        if (dateString != null) {
            int dateStringLen = dateString.length();
            int timeStringOffset = (clockDatePosition == STYLE_DATE_RIGHT) ? timeResult.length() + 1 : 0;
            if (mClockDateDisplay == CLOCK_DATE_DISPLAY_GONE) {
                formatted.delete(0, dateStringLen);
            } else {
                if (mClockDateDisplay == CLOCK_DATE_DISPLAY_SMALL) {
                    CharacterStyle style = new RelativeSizeSpan(0.7f);
                    formatted.setSpan(style, timeStringOffset, timeStringOffset + dateStringLen, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                }
            }
        }
    }
    if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
        int magic1 = result.indexOf(MAGIC1);
        int magic2 = result.indexOf(MAGIC2);
        if (magic1 >= 0 && magic2 > magic1) {
            if (mAmPmStyle == AM_PM_STYLE_GONE) {
                formatted.delete(magic1, magic2 + 1);
            } else {
                if (mAmPmStyle == AM_PM_STYLE_SMALL) {
                    CharacterStyle style = new RelativeSizeSpan(0.7f);
                    formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                }
                formatted.delete(magic2, magic2 + 1);
                formatted.delete(magic1, magic1 + 1);
            }
        }
    }
    return formatted;
}
Also used : Context(android.content.Context) LocaleData(libcore.icu.LocaleData) RelativeSizeSpan(android.text.style.RelativeSizeSpan) SimpleDateFormat(java.text.SimpleDateFormat) Date(java.util.Date) SpannableStringBuilder(android.text.SpannableStringBuilder) CharacterStyle(android.text.style.CharacterStyle)

Aggregations

CharacterStyle (android.text.style.CharacterStyle)58 SpannableStringBuilder (android.text.SpannableStringBuilder)22 ForegroundColorSpan (android.text.style.ForegroundColorSpan)18 RelativeSizeSpan (android.text.style.RelativeSizeSpan)18 Paint (android.graphics.Paint)16 AbsoluteSizeSpan (android.text.style.AbsoluteSizeSpan)14 StyleSpan (android.text.style.StyleSpan)13 TextPaint (android.text.TextPaint)12 ParcelableSpan (android.text.ParcelableSpan)9 SpannableString (android.text.SpannableString)9 Spanned (android.text.Spanned)9 StrikethroughSpan (android.text.style.StrikethroughSpan)9 TypefaceSpan (android.text.style.TypefaceSpan)9 UnderlineSpan (android.text.style.UnderlineSpan)9 BackgroundColorSpan (android.text.style.BackgroundColorSpan)8 ReplacementSpan (android.text.style.ReplacementSpan)8 SubscriptSpan (android.text.style.SubscriptSpan)8 SuperscriptSpan (android.text.style.SuperscriptSpan)8 URLSpan (android.text.style.URLSpan)8 ImageSpan (android.text.style.ImageSpan)7