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;
}
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);
}
}
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;
}
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>");
}
}
}
}
}
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;
}
Aggregations