Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
41d50c22
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
41d50c22
编写于
2月 05, 2020
作者:
M
Mouad Debbar
提交者:
GitHub
2月 05, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Reland #16206: "[web] Correct getPositionForOffset for multi-line paragraphs" (#16365)
上级
07f25c51
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
203 addition
and
8 deletion
+203
-8
lib/web_ui/lib/src/engine/text/measurement.dart
lib/web_ui/lib/src/engine/text/measurement.dart
+4
-1
lib/web_ui/lib/src/engine/text/paragraph.dart
lib/web_ui/lib/src/engine/text/paragraph.dart
+50
-6
lib/web_ui/test/paragraph_test.dart
lib/web_ui/test/paragraph_test.dart
+149
-1
未找到文件。
lib/web_ui/lib/src/engine/text/measurement.dart
浏览文件 @
41d50c22
...
...
@@ -373,7 +373,10 @@ class DomTextMeasurementService extends TextMeasurementService {
@override
ui
.
TextPosition
getTextPositionForOffset
(
EngineParagraph
paragraph
,
ui
.
ParagraphConstraints
constraints
,
ui
.
Offset
offset
)
{
assert
(
paragraph
.
_plainText
==
null
,
'should only be called for multispan'
);
assert
(
paragraph
.
_measurementResult
.
lines
==
null
,
'should only be called when the faster lines-based approach is not possible'
,
);
final
ParagraphGeometricStyle
style
=
paragraph
.
_geometricStyle
;
final
ParagraphRuler
ruler
=
...
...
lib/web_ui/lib/src/engine/text/paragraph.dart
浏览文件 @
41d50c22
...
...
@@ -378,17 +378,61 @@ class EngineParagraph implements ui.Paragraph {
@override
ui
.
TextPosition
getPositionForOffset
(
ui
.
Offset
offset
)
{
if
(
_plainText
==
null
)
{
final
List
<
EngineLineMetrics
>
lines
=
_measurementResult
.
lines
;
if
(
lines
==
null
)
{
return
getPositionForMultiSpanOffset
(
offset
);
}
// [offset] is above all the lines.
if
(
offset
.
dy
<
0
)
{
return
ui
.
TextPosition
(
offset:
0
,
affinity:
ui
.
TextAffinity
.
downstream
,
);
}
final
int
lineNumber
=
offset
.
dy
~/
_measurementResult
.
lineHeight
;
// [offset] is below all the lines.
if
(
lineNumber
>=
lines
.
length
)
{
return
ui
.
TextPosition
(
offset:
_plainText
.
length
,
affinity:
ui
.
TextAffinity
.
upstream
,
);
}
final
EngineLineMetrics
lineMetrics
=
lines
[
lineNumber
];
final
double
lineLeft
=
lineMetrics
.
left
;
final
double
lineRight
=
lineLeft
+
lineMetrics
.
width
;
// [offset] is to the left of the line.
if
(
offset
.
dx
<=
lineLeft
)
{
return
ui
.
TextPosition
(
offset:
lineMetrics
.
startIndex
,
affinity:
ui
.
TextAffinity
.
downstream
,
);
}
// [offset] is to the right of the line.
if
(
offset
.
dx
>=
lineRight
)
{
return
ui
.
TextPosition
(
offset:
lineMetrics
.
endIndex
,
affinity:
ui
.
TextAffinity
.
upstream
,
);
}
// If we reach here, it means the [offset] is somewhere within the line. The
// code below will do a binary search to find where exactly the [offset]
// falls within the line.
final
double
dx
=
offset
.
dx
-
_alignOffset
;
final
TextMeasurementService
instance
=
_measurementService
;
int
low
=
0
;
int
high
=
_plainText
.
length
;
int
low
=
lineMetrics
.
startIndex
;
int
high
=
lineMetrics
.
endIndex
;
do
{
final
int
current
=
(
low
+
high
)
~/
2
;
final
double
width
=
instance
.
measureSubstringWidth
(
this
,
0
,
current
);
final
double
width
=
instance
.
measureSubstringWidth
(
this
,
lineMetrics
.
startIndex
,
current
);
if
(
width
<
dx
)
{
low
=
current
;
}
else
if
(
width
>
dx
)
{
...
...
@@ -403,8 +447,8 @@ class EngineParagraph implements ui.Paragraph {
return
ui
.
TextPosition
(
offset:
high
,
affinity:
ui
.
TextAffinity
.
upstream
);
}
final
double
lowWidth
=
instance
.
measureSubstringWidth
(
this
,
0
,
low
);
final
double
highWidth
=
instance
.
measureSubstringWidth
(
this
,
0
,
high
);
final
double
lowWidth
=
instance
.
measureSubstringWidth
(
this
,
lineMetrics
.
startIndex
,
low
);
final
double
highWidth
=
instance
.
measureSubstringWidth
(
this
,
lineMetrics
.
startIndex
,
high
);
if
(
dx
-
lowWidth
<
highWidth
-
dx
)
{
// The offset is closer to the low index.
...
...
lib/web_ui/test/paragraph_test.dart
浏览文件 @
41d50c22
...
...
@@ -8,7 +8,7 @@ import 'package:ui/ui.dart';
import
'package:test/test.dart'
;
void
testEachMeasurement
(
String
description
,
VoidCallback
body
,
{
bool
skip
})
{
test
(
description
,
()
async
{
test
(
'
$description
(dom measurement)'
,
()
async
{
try
{
TextMeasurementService
.
initialize
(
rulerCacheCapacity:
2
);
return
body
();
...
...
@@ -130,6 +130,154 @@ void main() async {
},
// TODO(nurhan): https://github.com/flutter/flutter/issues/46638
skip:
(
browserEngine
==
BrowserEngine
.
firefox
));
testEachMeasurement
(
'getPositionForOffset single-line'
,
()
{
final
ParagraphBuilder
builder
=
ParagraphBuilder
(
ParagraphStyle
(
fontFamily:
'Ahem'
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
normal
,
fontSize:
10
,
textDirection:
TextDirection
.
ltr
,
));
builder
.
addText
(
'abcd efg'
);
final
Paragraph
paragraph
=
builder
.
build
();
paragraph
.
layout
(
const
ParagraphConstraints
(
width:
1000
));
// At the beginning of the line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
5
)),
TextPosition
(
offset:
0
,
affinity:
TextAffinity
.
downstream
),
);
// Below the line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
12
)),
TextPosition
(
offset:
8
,
affinity:
TextAffinity
.
upstream
),
);
// Above the line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
-
5
)),
TextPosition
(
offset:
0
,
affinity:
TextAffinity
.
downstream
),
);
// At the end of the line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
80
,
5
)),
TextPosition
(
offset:
8
,
affinity:
TextAffinity
.
upstream
),
);
// On the left side of "b".
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
14
,
5
)),
TextPosition
(
offset:
1
,
affinity:
TextAffinity
.
downstream
),
);
// On the right side of "b".
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
16
,
5
)),
TextPosition
(
offset:
2
,
affinity:
TextAffinity
.
upstream
),
);
});
test
(
'getPositionForOffset multi-line'
,
()
{
// [Paragraph.getPositionForOffset] for multi-line text doesn't work well
// with dom-based measurement.
TextMeasurementService
.
enableExperimentalCanvasImplementation
=
true
;
TextMeasurementService
.
initialize
(
rulerCacheCapacity:
2
);
final
ParagraphBuilder
builder
=
ParagraphBuilder
(
ParagraphStyle
(
fontFamily:
'Ahem'
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
normal
,
fontSize:
10
,
textDirection:
TextDirection
.
ltr
,
));
builder
.
addText
(
'abcd
\n
'
);
builder
.
addText
(
'abcdefg
\n
'
);
builder
.
addText
(
'ab'
);
final
Paragraph
paragraph
=
builder
.
build
();
paragraph
.
layout
(
const
ParagraphConstraints
(
width:
1000
));
// First line: "abcd\n"
// At the beginning of the first line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
5
)),
TextPosition
(
offset:
0
,
affinity:
TextAffinity
.
downstream
),
);
// Above the first line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
-
15
)),
TextPosition
(
offset:
0
,
affinity:
TextAffinity
.
downstream
),
);
// At the end of the first line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
50
,
5
)),
TextPosition
(
offset:
5
,
affinity:
TextAffinity
.
upstream
),
);
// On the left side of "b" in the first line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
14
,
5
)),
TextPosition
(
offset:
1
,
affinity:
TextAffinity
.
downstream
),
);
// On the right side of "b" in the first line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
16
,
5
)),
TextPosition
(
offset:
2
,
affinity:
TextAffinity
.
upstream
),
);
// Second line: "abcdefg\n"
// At the beginning of the second line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
15
)),
TextPosition
(
offset:
5
,
affinity:
TextAffinity
.
downstream
),
);
// At the end of the second line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
100
,
15
)),
TextPosition
(
offset:
13
,
affinity:
TextAffinity
.
upstream
),
);
// On the left side of "e" in the second line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
44
,
15
)),
TextPosition
(
offset:
9
,
affinity:
TextAffinity
.
downstream
),
);
// On the right side of "e" in the second line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
46
,
15
)),
TextPosition
(
offset:
10
,
affinity:
TextAffinity
.
upstream
),
);
// Last (third) line: "ab"
// At the beginning of the last line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
25
)),
TextPosition
(
offset:
13
,
affinity:
TextAffinity
.
downstream
),
);
// At the end of the last line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
40
,
25
)),
TextPosition
(
offset:
15
,
affinity:
TextAffinity
.
upstream
),
);
// Below the last line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
0
,
32
)),
TextPosition
(
offset:
15
,
affinity:
TextAffinity
.
upstream
),
);
// On the left side of "b" in the last line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
12
,
25
)),
TextPosition
(
offset:
14
,
affinity:
TextAffinity
.
downstream
),
);
// On the right side of "a" in the last line.
expect
(
paragraph
.
getPositionForOffset
(
Offset
(
9
,
25
)),
TextPosition
(
offset:
14
,
affinity:
TextAffinity
.
upstream
),
);
TextMeasurementService
.
clearCache
();
TextMeasurementService
.
enableExperimentalCanvasImplementation
=
false
;
});
testEachMeasurement
(
'getBoxesForRange returns a box'
,
()
{
final
ParagraphBuilder
builder
=
ParagraphBuilder
(
ParagraphStyle
(
fontFamily:
'Ahem'
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录