|
1 | 1 | using System.Collections.Generic;
|
| 2 | +using System.Runtime.CompilerServices; |
2 | 3 | using Unity.UIWidgets.foundation;
|
3 | 4 | using Unity.UIWidgets.service;
|
4 | 5 | using Unity.UIWidgets.ui;
|
|
7 | 8 | using Rect = Unity.UIWidgets.ui.Rect;
|
8 | 9 |
|
9 | 10 | namespace Unity.UIWidgets.painting {
|
| 11 | + |
| 12 | + class _CaretMetrics { |
| 13 | + public _CaretMetrics(Offset offset, float? fullHeight) { |
| 14 | + this.offset = offset; |
| 15 | + this.fullHeight = fullHeight; |
| 16 | + } |
| 17 | + |
| 18 | + public Offset offset; |
| 19 | + public float? fullHeight; |
| 20 | + } |
10 | 21 | public class TextPainter {
|
11 | 22 | TextSpan _text;
|
12 | 23 | TextAlign _textAlign;
|
@@ -224,29 +235,38 @@ public void paint(Canvas canvas, Offset offset) {
|
224 | 235 | }
|
225 | 236 |
|
226 | 237 | public Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) {
|
| 238 | + this._computeCaretMetrics(position, caretPrototype); |
| 239 | + return this._caretMetrics.offset; |
| 240 | + } |
| 241 | + |
| 242 | + _CaretMetrics _caretMetrics; |
| 243 | + |
| 244 | + TextPosition _previousCaretPosition; |
| 245 | + Rect _previousCaretPrototype; |
| 246 | + |
| 247 | + void _computeCaretMetrics(TextPosition position, Rect caretPrototype) { |
227 | 248 | D.assert(!this._needsLayout);
|
228 |
| - var offset = position.offset; |
229 |
| - if (offset > 0) { |
230 |
| - var prevCodeUnit = this._text.codeUnitAt(offset); |
231 |
| - if (prevCodeUnit == null) // out of upper bounds |
232 |
| - { |
233 |
| - var rectNextLine = this._paragraph.getNextLineStartRect(); |
234 |
| - if (rectNextLine != null) { |
235 |
| - return new Offset(rectNextLine.start, rectNextLine.top); |
236 |
| - } |
237 |
| - } |
| 249 | + if (position == this._previousCaretPosition && caretPrototype == this._previousCaretPrototype) { |
| 250 | + return; |
238 | 251 | }
|
239 |
| - |
| 252 | + var offset = position.offset; |
| 253 | + Rect rect; |
240 | 254 | switch (position.affinity) {
|
241 | 255 | case TextAffinity.upstream:
|
242 |
| - return this._getOffsetFromUpstream(offset, caretPrototype) ?? |
243 |
| - this._getOffsetFromDownstream(offset, caretPrototype) ?? this._emptyOffset; |
| 256 | + rect = this._getRectFromUpstream(offset, caretPrototype) ?? |
| 257 | + this._getRectFromDownStream(offset, caretPrototype); |
| 258 | + break; |
244 | 259 | case TextAffinity.downstream:
|
245 |
| - return this._getOffsetFromDownstream(offset, caretPrototype) ?? |
246 |
| - this._getOffsetFromUpstream(offset, caretPrototype) ?? this._emptyOffset; |
| 260 | + rect = this._getRectFromDownStream(offset, caretPrototype) ?? |
| 261 | + this._getRectFromUpstream(offset, caretPrototype); |
| 262 | + break; |
| 263 | + default: |
| 264 | + throw new UIWidgetsError("Unknown Position Affinity"); |
247 | 265 | }
|
248 | 266 |
|
249 |
| - return null; |
| 267 | + this._caretMetrics = new _CaretMetrics( |
| 268 | + offset: rect != null ? new Offset(rect.left, rect.top) : this._emptyOffset, |
| 269 | + fullHeight: rect != null ? (float?) (rect.bottom - rect.top) : null); |
250 | 270 | }
|
251 | 271 |
|
252 | 272 | public Paragraph.LineRange getLineRange(int lineNumber) {
|
@@ -372,7 +392,7 @@ float _applyFloatingPointHack(float layoutValue) {
|
372 | 392 |
|
373 | 393 | const int _zwjUtf16 = 0x200d;
|
374 | 394 |
|
375 |
| - Offset _getOffsetFromUpstream(int offset, Rect caretPrototype) { |
| 395 | + Rect _getRectFromUpstream(int offset, Rect caretPrototype) { |
376 | 396 | string flattenedText = this._text.toPlainText();
|
377 | 397 | var prevCodeUnit = this._text.codeUnitAt(Mathf.Max(0, offset - 1));
|
378 | 398 | if (prevCodeUnit == null) {
|
@@ -401,18 +421,20 @@ Offset _getOffsetFromUpstream(int offset, Rect caretPrototype) {
|
401 | 421 | TextBox box = boxes[0];
|
402 | 422 | const int NEWLINE_CODE_UNIT = 10;
|
403 | 423 | if (prevCodeUnit == NEWLINE_CODE_UNIT) {
|
404 |
| - return new Offset(this._emptyOffset.dx, box.bottom); |
| 424 | + return Rect.fromLTRB(this._emptyOffset.dx, box.bottom, |
| 425 | + this._emptyOffset.dx, box.bottom + box.bottom - box.top); |
405 | 426 | }
|
406 | 427 |
|
407 | 428 | float caretEnd = box.end;
|
408 | 429 | float dx = box.direction == TextDirection.rtl ? caretEnd - caretPrototype.width : caretEnd;
|
409 |
| - return new Offset(dx, box.top); |
| 430 | + return Rect.fromLTRB(Mathf.Min(dx, this.width), box.top, |
| 431 | + Mathf.Min(dx, this.width), box.bottom); |
410 | 432 | }
|
411 | 433 |
|
412 | 434 | return null;
|
413 | 435 | }
|
414 | 436 |
|
415 |
| - Offset _getOffsetFromDownstream(int offset, Rect caretPrototype) { |
| 437 | + Rect _getRectFromDownStream(int offset, Rect caretPrototype) { |
416 | 438 | string flattenedText = this._text.toPlainText();
|
417 | 439 | var nextCodeUnit =
|
418 | 440 | this._text.codeUnitAt(Mathf.Min(offset, flattenedText == null ? 0 : flattenedText.Length - 1));
|
@@ -442,7 +464,8 @@ Offset _getOffsetFromDownstream(int offset, Rect caretPrototype) {
|
442 | 464 | TextBox box = boxes[boxes.Count - 1];
|
443 | 465 | float caretStart = box.start;
|
444 | 466 | float dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart;
|
445 |
| - return new Offset(dx, box.top); |
| 467 | + return Rect.fromLTRB(Mathf.Min(dx, this.width), box.top, |
| 468 | + Mathf.Min(dx, this.width), box.bottom); |
446 | 469 | }
|
447 | 470 |
|
448 | 471 | return null;
|
|
0 commit comments