|
1 |
| -using System; |
2 |
| -using System.Collections.Generic; |
| 1 | +using System.Collections.Generic; |
3 | 2 | using Unity.UIWidgets.foundation;
|
4 | 3 | using Unity.UIWidgets.service;
|
5 | 4 | using Unity.UIWidgets.ui;
|
@@ -66,7 +65,7 @@ public string ellipsis {
|
66 | 65 | public TextSpan text {
|
67 | 66 | get { return this._text; }
|
68 | 67 | set {
|
69 |
| - if ((this._text == null && value == null) || (this._text != null && this.text.Equals(value))) { |
| 68 | + if ((this._text == null && value == null) || (this._text != null && this.text.Equals(value))) { |
70 | 69 | return;
|
71 | 70 | }
|
72 | 71 |
|
@@ -353,41 +352,82 @@ float _applyFloatingPointHack(float layoutValue) {
|
353 | 352 | return Mathf.Ceil(layoutValue);
|
354 | 353 | }
|
355 | 354 |
|
| 355 | + const int _zwjUtf16 = 0x200d; |
356 | 356 |
|
357 | 357 | Offset _getOffsetFromUpstream(int offset, Rect caretPrototype) {
|
358 |
| - var prevCodeUnit = this._text.codeUnitAt(offset - 1); |
| 358 | + string flattenedText = this._text.toPlainText(); |
| 359 | + var prevCodeUnit = this._text.codeUnitAt(Mathf.Max(0, offset - 1)); |
359 | 360 | if (prevCodeUnit == null) {
|
360 | 361 | return null;
|
361 | 362 | }
|
362 | 363 |
|
363 |
| - var prevRuneOffset = _isUtf16Surrogate((int) prevCodeUnit) ? offset - 2 : offset - 1; |
364 |
| - var boxes = this._paragraph.getRectsForRange(prevRuneOffset, offset); |
365 |
| - if (boxes.Count == 0) { |
366 |
| - return null; |
| 364 | + bool needsSearch = _isUtf16Surrogate(prevCodeUnit.Value) || this._text.codeUnitAt(offset) == _zwjUtf16; |
| 365 | + int graphemeClusterLength = needsSearch ? 2 : 1; |
| 366 | + List<TextBox> boxes = null; |
| 367 | + while ((boxes == null || boxes.isEmpty()) && flattenedText != null) { |
| 368 | + int prevRuneOffset = offset - graphemeClusterLength; |
| 369 | + boxes = this._paragraph.getRectsForRange(prevRuneOffset, offset); |
| 370 | + if (boxes.isEmpty()) { |
| 371 | + if (!needsSearch) { |
| 372 | + break; |
| 373 | + } |
| 374 | + |
| 375 | + if (prevRuneOffset < -flattenedText.Length) { |
| 376 | + break; |
| 377 | + } |
| 378 | + |
| 379 | + graphemeClusterLength *= 2; |
| 380 | + continue; |
| 381 | + } |
| 382 | + |
| 383 | + TextBox box = boxes[0]; |
| 384 | + const int NEWLINE_CODE_UNIT = 10; |
| 385 | + if (prevCodeUnit == NEWLINE_CODE_UNIT) { |
| 386 | + return new Offset(this._emptyOffset.dx, box.bottom); |
| 387 | + } |
| 388 | + |
| 389 | + float caretEnd = box.end; |
| 390 | + float dx = box.direction == TextDirection.rtl ? caretEnd - caretPrototype.width : caretEnd; |
| 391 | + return new Offset(dx, box.top); |
367 | 392 | }
|
368 | 393 |
|
369 |
| - var box = boxes[0]; |
370 |
| - var caretEnd = box.end; |
371 |
| - var dx = box.direction == TextDirection.rtl ? caretEnd : caretEnd - caretPrototype.width; |
372 |
| - return new Offset(dx, box.top); |
| 394 | + return null; |
373 | 395 | }
|
374 | 396 |
|
375 | 397 | Offset _getOffsetFromDownstream(int offset, Rect caretPrototype) {
|
376 |
| - var nextCodeUnit = this._text.codeUnitAt(offset - 1); |
| 398 | + string flattenedText = this._text.toPlainText(); |
| 399 | + var nextCodeUnit = |
| 400 | + this._text.codeUnitAt(Mathf.Min(offset, flattenedText == null ? 0 : flattenedText.Length - 1)); |
377 | 401 | if (nextCodeUnit == null) {
|
378 | 402 | return null;
|
379 | 403 | }
|
380 | 404 |
|
381 |
| - var nextRuneOffset = _isUtf16Surrogate((int) nextCodeUnit) ? offset + 2 : offset + 1; |
382 |
| - var boxes = this._paragraph.getRectsForRange(offset, nextRuneOffset); |
383 |
| - if (boxes.Count == 0) { |
384 |
| - return null; |
| 405 | + bool needsSearch = _isUtf16Surrogate(nextCodeUnit.Value) || nextCodeUnit == _zwjUtf16; |
| 406 | + int graphemeClusterLength = needsSearch ? 2 : 1; |
| 407 | + List<TextBox> boxes = null; |
| 408 | + while ((boxes == null || boxes.isEmpty()) && flattenedText != null) { |
| 409 | + int nextRuneOffset = offset + graphemeClusterLength; |
| 410 | + boxes = this._paragraph.getRectsForRange(offset, nextRuneOffset); |
| 411 | + if (boxes.isEmpty()) { |
| 412 | + if (!needsSearch) { |
| 413 | + break; |
| 414 | + } |
| 415 | + |
| 416 | + if (nextRuneOffset >= flattenedText.Length << 1) { |
| 417 | + break; |
| 418 | + } |
| 419 | + |
| 420 | + graphemeClusterLength *= 2; |
| 421 | + continue; |
| 422 | + } |
| 423 | + |
| 424 | + TextBox box = boxes[boxes.Count - 1]; |
| 425 | + float caretStart = box.start; |
| 426 | + float dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart; |
| 427 | + return new Offset(dx, box.top); |
385 | 428 | }
|
386 | 429 |
|
387 |
| - var box = boxes[0]; |
388 |
| - var caretStart = box.start; |
389 |
| - var dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart; |
390 |
| - return new Offset(dx, box.top); |
| 430 | + return null; |
391 | 431 | }
|
392 | 432 |
|
393 | 433 | Offset _emptyOffset {
|
|
0 commit comments