Skip to content

Commit 646a404

Browse files
Gilles DebunneAndroid (Google) Code Review
authored andcommitted
Merge "Refactoring SpannableStringBuilder"
2 parents 5a7a1db + b51036f commit 646a404

File tree

1 file changed

+52
-80
lines changed

1 file changed

+52
-80
lines changed

core/java/android/text/SpannableStringBuilder.java

Lines changed: 52 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,8 @@ public SpannableStringBuilder append(char text) {
262262
return append(String.valueOf(text));
263263
}
264264

265-
private int change(int start, int end, CharSequence tb, int tbstart, int tbend) {
266-
return change(true, start, end, tb, tbstart, tbend);
267-
}
268-
269-
private int change(boolean notify, int start, int end,
270-
CharSequence tb, int tbstart, int tbend) {
265+
private void change(int start, int end, CharSequence tb, int tbstart, int tbend) {
271266
checkRange("replace", start, end);
272-
int ret = tbend - tbstart;
273-
TextWatcher[] recipients = null;
274-
275-
if (notify) {
276-
recipients = sendTextWillChange(start, end - start, tbend - tbstart);
277-
}
278267

279268
for (int i = mSpanCount - 1; i >= 0; i--) {
280269
if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) {
@@ -338,59 +327,45 @@ private int change(boolean notify, int start, int end,
338327
en = tbend;
339328

340329
if (getSpanStart(spans[i]) < 0) {
341-
setSpan(true, spans[i],
330+
setSpan(false, spans[i],
342331
st - tbstart + start,
343332
en - tbstart + start,
344333
sp.getSpanFlags(spans[i]));
345334
}
346335
}
347336
}
348337

349-
// no need for span fixup on pure insertion
350-
if (tbend > tbstart && end - start == 0) {
351-
if (notify) {
352-
sendTextChange(recipients, start, end - start, tbend - tbstart);
353-
sendTextHasChanged(recipients);
354-
}
355-
356-
return ret;
357-
}
358-
359-
boolean atend = (mGapStart + mGapLength == mText.length);
338+
if (end > start) {
339+
// no need for span fixup on pure insertion
340+
boolean atEnd = (mGapStart + mGapLength == mText.length);
360341

361-
for (int i = mSpanCount - 1; i >= 0; i--) {
362-
if (mSpanStarts[i] >= start &&
363-
mSpanStarts[i] < mGapStart + mGapLength) {
364-
int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
342+
for (int i = mSpanCount - 1; i >= 0; i--) {
343+
if (mSpanStarts[i] >= start &&
344+
mSpanStarts[i] < mGapStart + mGapLength) {
345+
int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
365346

366-
if (flag == POINT || (flag == PARAGRAPH && atend))
347+
if (flag == POINT || (flag == PARAGRAPH && atEnd))
367348
mSpanStarts[i] = mGapStart + mGapLength;
368349
else
369350
mSpanStarts[i] = start;
370-
}
351+
}
371352

372-
if (mSpanEnds[i] >= start &&
373-
mSpanEnds[i] < mGapStart + mGapLength) {
374-
int flag = (mSpanFlags[i] & END_MASK);
353+
if (mSpanEnds[i] >= start &&
354+
mSpanEnds[i] < mGapStart + mGapLength) {
355+
int flag = (mSpanFlags[i] & END_MASK);
375356

376-
if (flag == POINT || (flag == PARAGRAPH && atend))
377-
mSpanEnds[i] = mGapStart + mGapLength;
378-
else
379-
mSpanEnds[i] = start;
380-
}
357+
if (flag == POINT || (flag == PARAGRAPH && atEnd))
358+
mSpanEnds[i] = mGapStart + mGapLength;
359+
else
360+
mSpanEnds[i] = start;
361+
}
381362

382-
// remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
383-
if (mSpanEnds[i] < mSpanStarts[i]) {
384-
removeSpan(i);
363+
// remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
364+
if (mSpanEnds[i] < mSpanStarts[i]) {
365+
removeSpan(i);
366+
}
385367
}
386368
}
387-
388-
if (notify) {
389-
sendTextChange(recipients, start, end - start, tbend - tbstart);
390-
sendTextHasChanged(recipients);
391-
}
392-
393-
return ret;
394369
}
395370

396371
private void removeSpan(int i) {
@@ -425,8 +400,7 @@ public SpannableStringBuilder replace(final int start, final int end,
425400
CharSequence tb, int tbstart, int tbend) {
426401
int filtercount = mFilters.length;
427402
for (int i = 0; i < filtercount; i++) {
428-
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend,
429-
this, start, end);
403+
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
430404

431405
if (repl != null) {
432406
tb = repl;
@@ -435,11 +409,17 @@ public SpannableStringBuilder replace(final int start, final int end,
435409
}
436410
}
437411

438-
if (end == start && tbstart == tbend) {
412+
final int origLen = end - start;
413+
final int newLen = tbend - tbstart;
414+
415+
if (origLen == 0 && newLen == 0) {
439416
return this;
440417
}
441418

442-
if (end == start || tbstart == tbend) {
419+
TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
420+
sendBeforeTextChanged(textWatchers, start, origLen, newLen);
421+
422+
if (origLen == 0 || newLen == 0) {
443423
change(start, end, tb, tbstart, tbend);
444424
} else {
445425
int selstart = Selection.getSelectionStart(this);
@@ -450,11 +430,6 @@ public SpannableStringBuilder replace(final int start, final int end,
450430

451431
checkRange("replace", start, end);
452432
moveGapTo(end);
453-
TextWatcher[] recipients;
454-
455-
int origlen = end - start;
456-
457-
recipients = sendTextWillChange(start, origlen, tbend - tbstart);
458433

459434
if (mGapLength < 2)
460435
resizeFor(length() + 1);
@@ -475,9 +450,9 @@ public SpannableStringBuilder replace(final int start, final int end,
475450
new Exception("mGapLength < 1").printStackTrace();
476451
}
477452

478-
int inserted = change(false, start + 1, start + 1, tb, tbstart, tbend);
479-
change(false, start, start + 1, "", 0, 0);
480-
change(false, start + inserted, start + inserted + origlen, "", 0, 0);
453+
change(start + 1, start + 1, tb, tbstart, tbend);
454+
change(start, start + 1, "", 0, 0);
455+
change(start + newLen, start + newLen + origLen, "", 0, 0);
481456

482457
/*
483458
* Special case to keep the cursor in the same position
@@ -490,7 +465,7 @@ public SpannableStringBuilder replace(final int start, final int end,
490465
if (selstart > start && selstart < end) {
491466
long off = selstart - start;
492467

493-
off = off * inserted / (end - start);
468+
off = off * newLen / (end - start);
494469
selstart = (int) off + start;
495470

496471
setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -499,15 +474,16 @@ public SpannableStringBuilder replace(final int start, final int end,
499474
if (selend > start && selend < end) {
500475
long off = selend - start;
501476

502-
off = off * inserted / (end - start);
477+
off = off * newLen / (end - start);
503478
selend = (int) off + start;
504479

505480
setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
506481
}
507-
sendTextChange(recipients, start, origlen, inserted);
508-
sendTextHasChanged(recipients);
509482
}
510483

484+
sendTextChanged(textWatchers, start, origLen, newLen);
485+
sendAfterTextChanged(textWatchers);
486+
511487
return this;
512488
}
513489

@@ -872,30 +848,27 @@ public String substring(int start, int end) {
872848
return new String(buf);
873849
}
874850

875-
private TextWatcher[] sendTextWillChange(int start, int before, int after) {
876-
TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class);
877-
int n = recip.length;
851+
private void sendBeforeTextChanged(TextWatcher[] watchers, int start, int before, int after) {
852+
int n = watchers.length;
878853

879854
for (int i = 0; i < n; i++) {
880-
recip[i].beforeTextChanged(this, start, before, after);
855+
watchers[i].beforeTextChanged(this, start, before, after);
881856
}
882-
883-
return recip;
884857
}
885858

886-
private void sendTextChange(TextWatcher[] recip, int start, int before, int after) {
887-
int n = recip.length;
859+
private void sendTextChanged(TextWatcher[] watchers, int start, int before, int after) {
860+
int n = watchers.length;
888861

889862
for (int i = 0; i < n; i++) {
890-
recip[i].onTextChanged(this, start, before, after);
863+
watchers[i].onTextChanged(this, start, before, after);
891864
}
892865
}
893866

894-
private void sendTextHasChanged(TextWatcher[] recip) {
895-
int n = recip.length;
867+
private void sendAfterTextChanged(TextWatcher[] watchers) {
868+
int n = watchers.length;
896869

897870
for (int i = 0; i < n; i++) {
898-
recip[i].afterTextChanged(this);
871+
watchers[i].afterTextChanged(this);
899872
}
900873
}
901874

@@ -1037,8 +1010,7 @@ public void dump() { // XXX
10371010
* Don't call this yourself -- exists for Canvas to use internally.
10381011
* {@hide}
10391012
*/
1040-
public void drawText(Canvas c, int start, int end,
1041-
float x, float y, Paint p) {
1013+
public void drawText(Canvas c, int start, int end, float x, float y, Paint p) {
10421014
checkRange("drawText", start, end);
10431015

10441016
if (end <= mGapStart) {
@@ -1059,8 +1031,7 @@ public void drawText(Canvas c, int start, int end,
10591031
* Don't call this yourself -- exists for Canvas to use internally.
10601032
* {@hide}
10611033
*/
1062-
public void drawTextRun(Canvas c, int start, int end,
1063-
int contextStart, int contextEnd,
1034+
public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
10641035
float x, float y, int flags, Paint p) {
10651036
checkRange("drawTextRun", start, end);
10661037

@@ -1262,6 +1233,7 @@ public InputFilter[] getFilters() {
12621233
private int[] mSpanFlags;
12631234
private int mSpanCount;
12641235

1236+
// TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
12651237
private static final int POINT = 2;
12661238
private static final int PARAGRAPH = 3;
12671239

0 commit comments

Comments
 (0)