use of android.text.style.CharacterStyle in project WordPress-Android by wordpress-mobile.
the class EditPostActivity method updatePostContent.
// TODO: Replace with contents of the updatePostContentNewEditor() method when legacy editor is dropped
/**
* Updates post object with content of this fragment
*/
public void updatePostContent(boolean isAutoSave) throws IllegalEditorStateException {
if (mPost == null) {
return;
}
String title = StringUtils.notNullStr((String) mEditorFragment.getTitle());
SpannableStringBuilder postContent;
if (mEditorFragment.getSpannedContent() != null) {
// needed by the legacy editor to save local drafts
try {
postContent = new SpannableStringBuilder(mEditorFragment.getSpannedContent());
} catch (IndexOutOfBoundsException e) {
// A core android bug might cause an out of bounds exception, if so we'll just use the current editable
// See https://code.google.com/p/android/issues/detail?id=5164
postContent = new SpannableStringBuilder(StringUtils.notNullStr((String) mEditorFragment.getContent()));
}
} else {
postContent = new SpannableStringBuilder(StringUtils.notNullStr((String) mEditorFragment.getContent()));
}
String content;
if (mPost.isLocalDraft()) {
// remove suggestion spans, they cause craziness in WPHtml.toHTML().
CharacterStyle[] characterStyles = postContent.getSpans(0, postContent.length(), CharacterStyle.class);
for (CharacterStyle characterStyle : characterStyles) {
if (characterStyle instanceof SuggestionSpan) {
postContent.removeSpan(characterStyle);
}
}
content = WPHtml.toHtml(postContent);
// replace duplicate <p> tags so there's not duplicates, trac #86
content = content.replace("<p><p>", "<p>");
content = content.replace("</p></p>", "</p>");
content = content.replace("<br><br>", "<br>");
// sometimes the editor creates extra tags
content = content.replace("</strong><strong>", "").replace("</em><em>", "").replace("</u><u>", "").replace("</strike><strike>", "").replace("</blockquote><blockquote>", "");
} else {
if (!isAutoSave) {
// Add gallery shortcode
MediaGalleryImageSpan[] gallerySpans = postContent.getSpans(0, postContent.length(), MediaGalleryImageSpan.class);
for (MediaGalleryImageSpan gallerySpan : gallerySpans) {
int start = postContent.getSpanStart(gallerySpan);
postContent.removeSpan(gallerySpan);
postContent.insert(start, WPHtml.getGalleryShortcode(gallerySpan));
}
}
WPImageSpan[] imageSpans = postContent.getSpans(0, postContent.length(), WPImageSpan.class);
if (imageSpans.length != 0) {
for (WPImageSpan wpIS : imageSpans) {
MediaFile mediaFile = wpIS.getMediaFile();
if (mediaFile == null) {
continue;
}
if (mediaFile.getMediaId() != null) {
updateMediaFileOnServer(mediaFile);
} else {
mediaFile.setFileName(wpIS.getImageSource().toString());
mediaFile.setFilePath(wpIS.getImageSource().toString());
}
int tagStart = postContent.getSpanStart(wpIS);
if (!isAutoSave) {
postContent.removeSpan(wpIS);
// network image has a mediaId
if (mediaFile.getMediaId() != null && mediaFile.getMediaId().length() > 0) {
postContent.insert(tagStart, WPHtml.getContent(wpIS));
} else {
// local image for upload
postContent.insert(tagStart, "<img android-uri=\"" + wpIS.getImageSource().toString() + "\" />");
}
}
}
}
content = postContent.toString();
}
mPost.setTitle(title);
mPost.setContent(content);
if (!mPost.isLocalDraft()) {
mPost.setIsLocallyChanged(true);
}
}
use of android.text.style.CharacterStyle in project platform_frameworks_base by android.
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 WordPress-Android by wordpress-mobile.
the class WPHtml method withinParagraph.
private static void withinParagraph(StringBuilder out, Spanned text, int start, int end, int nl, boolean last) {
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("<strong>");
}
if ((s & Typeface.ITALIC) != 0) {
out.append("<em>");
}
}
if (style[j] instanceof TypefaceSpan) {
String s = ((TypefaceSpan) style[j]).getFamily();
if (s.equals("monospace")) {
out.append("<tt>");
}
}
if (style[j] instanceof SuperscriptSpan) {
out.append("<sup>");
}
if (style[j] instanceof SubscriptSpan) {
out.append("<sub>");
}
if (style[j] instanceof WPUnderlineSpan) {
out.append("<u>");
}
if (style[j] instanceof StrikethroughSpan) {
out.append("<strike>");
}
if (style[j] instanceof URLSpan) {
out.append("<a href=\"");
out.append(((URLSpan) style[j]).getURL());
out.append("\">");
}
if (style[j] instanceof MediaGalleryImageSpan) {
out.append(getGalleryShortcode((MediaGalleryImageSpan) style[j]));
} else if (style[j] instanceof WPImageSpan && ((WPImageSpan) style[j]).getMediaFile().getMediaId() != null) {
out.append(getContent((WPImageSpan) style[j]));
} else if (style[j] instanceof WPImageSpan) {
out.append("<img src=\"");
out.append(((WPImageSpan) style[j]).getSource());
out.append("\" android-uri=\"" + ((WPImageSpan) style[j]).getImageSource().toString() + "\"");
out.append(" />");
// Don't output the dummy character underlying the image.
i = next;
}
if (style[j] instanceof AbsoluteSizeSpan) {
out.append("<font size =\"");
out.append(((AbsoluteSizeSpan) style[j]).getSize() / 6);
out.append("\">");
}
if (style[j] instanceof ForegroundColorSpan) {
out.append("<font color =\"#");
String color = Integer.toHexString(((ForegroundColorSpan) style[j]).getForegroundColor() + 0x01000000);
while (color.length() < 6) {
color = "0" + color;
}
out.append(color);
out.append("\">");
}
}
processWPImage(out, text, i, next);
for (int j = style.length - 1; j >= 0; j--) {
if (style[j] instanceof ForegroundColorSpan) {
out.append("</font>");
}
if (style[j] instanceof AbsoluteSizeSpan) {
out.append("</font>");
}
if (style[j] instanceof URLSpan) {
out.append("</a>");
}
if (style[j] instanceof StrikethroughSpan) {
out.append("</strike>");
}
if (style[j] instanceof WPUnderlineSpan) {
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("</strong>");
}
if ((s & Typeface.ITALIC) != 0) {
out.append("</em>");
}
}
}
}
String p = last ? "" : "</p>\n<p>";
if (nl == 1) {
out.append("<br>\n");
} else if (nl == 2) {
out.append(p);
} else {
for (int i = 2; i < nl; i++) {
out.append("<br>");
}
out.append(p);
}
}
use of android.text.style.CharacterStyle in project platform_frameworks_base by android.
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 crdroidandroid.
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;
}
Aggregations