Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
bcd8c715
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,发现更多精彩内容 >>
未验证
提交
bcd8c715
编写于
2月 16, 2021
作者:
Y
Yegor
提交者:
GitHub
2月 16, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix infinite loop in findMinimumFontsForCodeunits (#24441)
上级
df131a16
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
210 addition
and
53 deletion
+210
-53
lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart
lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart
+61
-50
lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart
lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart
+11
-1
lib/web_ui/lib/src/engine/canvaskit/text.dart
lib/web_ui/lib/src/engine/canvaskit/text.dart
+1
-1
lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart
lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart
+137
-1
未找到文件。
lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart
浏览文件 @
bcd8c715
...
...
@@ -12,7 +12,7 @@ bool _registeredSymbolsAndEmoji = false;
final
Set
<
int
>
codeUnitsWithNoKnownFont
=
<
int
>{};
Future
<
void
>
_
findFontsForMissingCodeunits
(
List
<
int
>
codeunits
)
async
{
Future
<
void
>
findFontsForMissingCodeunits
(
List
<
int
>
codeunits
)
async
{
_ensureNotoFontTreeCreated
();
// If all of the code units are known to have no Noto Font which covers them,
...
...
@@ -20,11 +20,11 @@ Future<void> _findFontsForMissingCodeunits(List<int> codeunits) async {
if
(
codeunits
.
every
((
u
)
=>
codeUnitsWithNoKnownFont
.
contains
(
u
)))
{
return
;
}
Set
<
_NotoFont
>
fonts
=
<
_
NotoFont
>{};
Set
<
NotoFont
>
fonts
=
<
NotoFont
>{};
Set
<
int
>
coveredCodeUnits
=
<
int
>{};
Set
<
int
>
missingCodeUnits
=
<
int
>{};
for
(
int
codeunit
in
codeunits
)
{
List
<
_
NotoFont
>
fontsForUnit
=
_notoTree
!.
intersections
(
codeunit
);
List
<
NotoFont
>
fontsForUnit
=
_notoTree
!.
intersections
(
codeunit
);
fonts
.
addAll
(
fontsForUnit
);
if
(
fontsForUnit
.
isNotEmpty
)
{
coveredCodeUnits
.
add
(
codeunit
);
...
...
@@ -33,15 +33,15 @@ Future<void> _findFontsForMissingCodeunits(List<int> codeunits) async {
}
}
fonts
=
_
findMinimumFontsForCodeunits
(
coveredCodeUnits
,
fonts
);
fonts
=
findMinimumFontsForCodeunits
(
coveredCodeUnits
,
fonts
);
for
(
_
NotoFont
font
in
fonts
)
{
for
(
NotoFont
font
in
fonts
)
{
await
font
.
ensureResolved
();
}
Set
<
_ResolvedNotoSubset
>
resolvedFonts
=
<
_ResolvedNotoSubset
>{};
for
(
int
codeunit
in
coveredCodeUnits
)
{
for
(
_
NotoFont
font
in
fonts
)
{
for
(
NotoFont
font
in
fonts
)
{
if
(
font
.
resolvedFont
==
null
)
{
// We failed to resolve the font earlier.
continue
;
...
...
@@ -232,18 +232,20 @@ Future<void> _registerSymbolsAndEmoji() async {
/// which finds the font which covers the most codeunits. If multiple CJK
/// fonts match the same number of codeunits, we choose one based on the user's
/// locale.
Set
<
_NotoFont
>
_findMinimumFontsForCodeunits
(
Iterable
<
int
>
codeunits
,
Set
<
_NotoFont
>
fonts
)
{
Set
<
NotoFont
>
findMinimumFontsForCodeunits
(
Iterable
<
int
>
codeunits
,
Set
<
NotoFont
>
fonts
)
{
assert
(
fonts
.
isNotEmpty
||
codeunits
.
isEmpty
);
List
<
int
>
unmatchedCodeunits
=
List
<
int
>.
from
(
codeunits
);
Set
<
_NotoFont
>
minimumFonts
=
<
_NotoFont
>{};
List
<
_NotoFont
>
bestFonts
=
<
_NotoFont
>[];
int
maxCodeunitsCovered
=
0
;
Set
<
NotoFont
>
minimumFonts
=
<
NotoFont
>{};
List
<
NotoFont
>
bestFonts
=
<
NotoFont
>[];
String
language
=
html
.
window
.
navigator
.
language
;
// This is guaranteed to terminate because [codeunits] is a list of fonts
// which we've already determined are covered by [fonts].
while
(
unmatchedCodeunits
.
isNotEmpty
)
{
int
maxCodeunitsCovered
=
0
;
bestFonts
.
clear
();
for
(
var
font
in
fonts
)
{
int
codeunitsCovered
=
0
;
for
(
int
codeunit
in
unmatchedCodeunits
)
{
...
...
@@ -259,10 +261,13 @@ Set<_NotoFont> _findMinimumFontsForCodeunits(
bestFonts
.
add
(
font
);
}
}
assert
(
bestFonts
.
isNotEmpty
);
assert
(
bestFonts
.
isNotEmpty
,
'Did not find any fonts that cover code units:
${unmatchedCodeunits.join(', ')}
'
,
);
// If the list of best fonts are all CJK fonts, choose the best one based
// on locale. Otherwise just choose the first font.
_
NotoFont
bestFont
=
bestFonts
.
first
;
NotoFont
bestFont
=
bestFonts
.
first
;
if
(
bestFonts
.
length
>
1
)
{
if
(
bestFonts
.
every
((
font
)
=>
_cjkFonts
.
contains
(
font
)))
{
if
(
language
==
'zh-Hans'
||
...
...
@@ -301,19 +306,19 @@ void _ensureNotoFontTreeCreated() {
return
;
}
Map
<
_
NotoFont
,
List
<
CodeunitRange
>>
ranges
=
<
_
NotoFont
,
List
<
CodeunitRange
>>{};
Map
<
NotoFont
,
List
<
CodeunitRange
>>
ranges
=
<
NotoFont
,
List
<
CodeunitRange
>>{};
for
(
_
NotoFont
font
in
_notoFonts
)
{
for
(
NotoFont
font
in
_notoFonts
)
{
for
(
CodeunitRange
range
in
font
.
unicodeRanges
)
{
ranges
.
putIfAbsent
(
font
,
()
=>
<
CodeunitRange
>[]).
add
(
range
);
}
}
_notoTree
=
IntervalTree
<
_
NotoFont
>.
createFromRanges
(
ranges
);
_notoTree
=
IntervalTree
<
NotoFont
>.
createFromRanges
(
ranges
);
}
class
_
NotoFont
{
class
NotoFont
{
final
String
name
;
final
List
<
CodeunitRange
>
unicodeRanges
;
...
...
@@ -321,7 +326,7 @@ class _NotoFont {
_ResolvedNotoFont
?
resolvedFont
;
_
NotoFont
(
this
.
name
,
this
.
unicodeRanges
);
NotoFont
(
this
.
name
,
this
.
unicodeRanges
);
bool
matchesCodeunit
(
int
codeunit
)
{
for
(
CodeunitRange
range
in
unicodeRanges
)
{
...
...
@@ -397,7 +402,7 @@ class _ResolvedNotoSubset {
String
toString
()
=>
'_ResolvedNotoSubset(
$family
,
$url
)'
;
}
_NotoFont
_notoSansSC
=
_
NotoFont
(
'Noto Sans SC'
,
<
CodeunitRange
>[
NotoFont
_notoSansSC
=
NotoFont
(
'Noto Sans SC'
,
<
CodeunitRange
>[
CodeunitRange
(
12288
,
12591
),
CodeunitRange
(
12800
,
13311
),
CodeunitRange
(
19968
,
40959
),
...
...
@@ -405,37 +410,37 @@ _NotoFont _notoSansSC = _NotoFont('Noto Sans SC', <CodeunitRange>[
CodeunitRange
(
65280
,
65519
),
]);
_NotoFont
_notoSansTC
=
_
NotoFont
(
'Noto Sans TC'
,
<
CodeunitRange
>[
NotoFont
_notoSansTC
=
NotoFont
(
'Noto Sans TC'
,
<
CodeunitRange
>[
CodeunitRange
(
12288
,
12351
),
CodeunitRange
(
12549
,
12585
),
CodeunitRange
(
19968
,
40959
),
]);
_NotoFont
_notoSansHK
=
_
NotoFont
(
'Noto Sans HK'
,
<
CodeunitRange
>[
NotoFont
_notoSansHK
=
NotoFont
(
'Noto Sans HK'
,
<
CodeunitRange
>[
CodeunitRange
(
12288
,
12351
),
CodeunitRange
(
12549
,
12585
),
CodeunitRange
(
19968
,
40959
),
]);
_NotoFont
_notoSansJP
=
_
NotoFont
(
'Noto Sans JP'
,
<
CodeunitRange
>[
NotoFont
_notoSansJP
=
NotoFont
(
'Noto Sans JP'
,
<
CodeunitRange
>[
CodeunitRange
(
12288
,
12543
),
CodeunitRange
(
19968
,
40959
),
CodeunitRange
(
65280
,
65519
),
]);
List
<
_NotoFont
>
_cjkFonts
=
<
_
NotoFont
>[
List
<
NotoFont
>
_cjkFonts
=
<
NotoFont
>[
_notoSansSC
,
_notoSansTC
,
_notoSansHK
,
_notoSansJP
,
];
List
<
_NotoFont
>
_notoFonts
=
<
_
NotoFont
>[
List
<
NotoFont
>
_notoFonts
=
<
NotoFont
>[
_notoSansSC
,
_notoSansTC
,
_notoSansHK
,
_notoSansJP
,
_
NotoFont
(
'Noto Naskh Arabic UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Naskh Arabic UI'
,
<
CodeunitRange
>[
CodeunitRange
(
1536
,
1791
),
CodeunitRange
(
8204
,
8206
),
CodeunitRange
(
8208
,
8209
),
...
...
@@ -444,36 +449,36 @@ List<_NotoFont> _notoFonts = <_NotoFont>[
CodeunitRange
(
64336
,
65023
),
CodeunitRange
(
65132
,
65276
),
]),
_
NotoFont
(
'Noto Sans Armenian'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Armenian'
,
<
CodeunitRange
>[
CodeunitRange
(
1328
,
1424
),
CodeunitRange
(
64275
,
64279
),
]),
_
NotoFont
(
'Noto Sans Bengali UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Bengali UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
2433
,
2555
),
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
8377
,
8377
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Myanmar UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Myanmar UI'
,
<
CodeunitRange
>[
CodeunitRange
(
4096
,
4255
),
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Egyptian Hieroglyphs'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Egyptian Hieroglyphs'
,
<
CodeunitRange
>[
CodeunitRange
(
77824
,
78894
),
]),
_
NotoFont
(
'Noto Sans Ethiopic'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Ethiopic'
,
<
CodeunitRange
>[
CodeunitRange
(
4608
,
5017
),
CodeunitRange
(
11648
,
11742
),
CodeunitRange
(
43777
,
43822
),
]),
_
NotoFont
(
'Noto Sans Georgian'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Georgian'
,
<
CodeunitRange
>[
CodeunitRange
(
1417
,
1417
),
CodeunitRange
(
4256
,
4351
),
CodeunitRange
(
11520
,
11567
),
]),
_
NotoFont
(
'Noto Sans Gujarati UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Gujarati UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
2688
,
2815
),
CodeunitRange
(
8204
,
8205
),
...
...
@@ -481,7 +486,7 @@ List<_NotoFont> _notoFonts = <_NotoFont>[
CodeunitRange
(
9676
,
9676
),
CodeunitRange
(
43056
,
43065
),
]),
_
NotoFont
(
'Noto Sans Gurmukhi UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Gurmukhi UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
2561
,
2677
),
CodeunitRange
(
8204
,
8205
),
...
...
@@ -490,13 +495,13 @@ List<_NotoFont> _notoFonts = <_NotoFont>[
CodeunitRange
(
9772
,
9772
),
CodeunitRange
(
43056
,
43065
),
]),
_
NotoFont
(
'Noto Sans Hebrew'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Hebrew'
,
<
CodeunitRange
>[
CodeunitRange
(
1424
,
1535
),
CodeunitRange
(
8362
,
8362
),
CodeunitRange
(
9676
,
9676
),
CodeunitRange
(
64285
,
64335
),
]),
_
NotoFont
(
'Noto Sans Devanagari UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Devanagari UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2304
,
2431
),
CodeunitRange
(
7376
,
7414
),
CodeunitRange
(
7416
,
7417
),
...
...
@@ -507,29 +512,29 @@ List<_NotoFont> _notoFonts = <_NotoFont>[
CodeunitRange
(
43056
,
43065
),
CodeunitRange
(
43232
,
43259
),
]),
_
NotoFont
(
'Noto Sans Kannada UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Kannada UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
3202
,
3314
),
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
8377
,
8377
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Khmer UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Khmer UI'
,
<
CodeunitRange
>[
CodeunitRange
(
6016
,
6143
),
CodeunitRange
(
8204
,
8204
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans KR'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans KR'
,
<
CodeunitRange
>[
CodeunitRange
(
12593
,
12686
),
CodeunitRange
(
12800
,
12828
),
CodeunitRange
(
12896
,
12923
),
CodeunitRange
(
44032
,
55215
),
]),
_
NotoFont
(
'Noto Sans Lao UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Lao UI'
,
<
CodeunitRange
>[
CodeunitRange
(
3713
,
3807
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Malayalam UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Malayalam UI'
,
<
CodeunitRange
>[
CodeunitRange
(
775
,
775
),
CodeunitRange
(
803
,
803
),
CodeunitRange
(
2404
,
2405
),
...
...
@@ -538,20 +543,20 @@ List<_NotoFont> _notoFonts = <_NotoFont>[
CodeunitRange
(
8377
,
8377
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Sinhala'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Sinhala'
,
<
CodeunitRange
>[
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
3458
,
3572
),
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Tamil UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Tamil UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
2946
,
3066
),
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
8377
,
8377
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Telugu UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Telugu UI'
,
<
CodeunitRange
>[
CodeunitRange
(
2385
,
2386
),
CodeunitRange
(
2404
,
2405
),
CodeunitRange
(
3072
,
3199
),
...
...
@@ -559,12 +564,12 @@ List<_NotoFont> _notoFonts = <_NotoFont>[
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans Thai UI'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans Thai UI'
,
<
CodeunitRange
>[
CodeunitRange
(
3585
,
3675
),
CodeunitRange
(
8204
,
8205
),
CodeunitRange
(
9676
,
9676
),
]),
_
NotoFont
(
'Noto Sans'
,
<
CodeunitRange
>[
NotoFont
(
'Noto Sans'
,
<
CodeunitRange
>[
CodeunitRange
(
0
,
255
),
CodeunitRange
(
305
,
305
),
CodeunitRange
(
338
,
339
),
...
...
@@ -639,7 +644,7 @@ class FallbackFontDownloadQueue {
downloads
.
add
(
Future
<
void
>(()
async
{
ByteBuffer
buffer
;
try
{
buffer
=
await
downloader
.
downloadAsBytes
(
subset
.
url
);
buffer
=
await
downloader
.
downloadAsBytes
(
subset
.
url
,
debugDescription:
subset
.
family
);
}
catch
(
e
)
{
html
.
window
.
console
.
warn
(
'Failed to load font
${subset.family}
at
${subset.url}
'
);
...
...
@@ -695,7 +700,7 @@ class NotoDownloader {
/// Downloads the [url] and returns it as a [ByteBuffer].
///
/// Override this for testing.
Future
<
ByteBuffer
>
downloadAsBytes
(
String
url
)
{
Future
<
ByteBuffer
>
downloadAsBytes
(
String
url
,
{
String
?
debugDescription
}
)
{
if
(
assertionsEnabled
)
{
_debugActiveDownloadCount
+=
1
;
}
...
...
@@ -714,7 +719,7 @@ class NotoDownloader {
/// Downloads the [url] and returns is as a [String].
///
/// Override this for testing.
Future
<
String
>
downloadAsString
(
String
url
)
{
Future
<
String
>
downloadAsString
(
String
url
,
{
String
?
debugDescription
}
)
{
if
(
assertionsEnabled
)
{
_debugActiveDownloadCount
+=
1
;
}
...
...
@@ -731,6 +736,12 @@ class NotoDownloader {
}
/// The Noto font interval tree.
IntervalTree
<
_NotoFont
>?
_notoTree
;
IntervalTree
<
NotoFont
>?
_notoTree
;
/// Returns the tree of Noto fonts for tests.
IntervalTree
<
NotoFont
>
get
debugNotoTree
{
_ensureNotoFontTreeCreated
();
return
_notoTree
!;
}
FallbackFontDownloadQueue
notoDownloadQueue
=
FallbackFontDownloadQueue
();
lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart
浏览文件 @
bcd8c715
...
...
@@ -18,7 +18,7 @@ class IntervalTree<T> {
/// have a range which contains the point.
factory
IntervalTree
.
createFromRanges
(
Map
<
T
,
List
<
CodeunitRange
>>
rangesMap
)
{
// Get a list of all the ranges ordered by start index.
List
<
IntervalTreeNode
<
T
>>
intervals
=
<
IntervalTreeNode
<
T
>>[];
final
List
<
IntervalTreeNode
<
T
>>
intervals
=
<
IntervalTreeNode
<
T
>>[];
rangesMap
.
forEach
((
T
key
,
List
<
CodeunitRange
>
rangeList
)
{
for
(
CodeunitRange
range
in
rangeList
)
{
intervals
.
add
(
IntervalTreeNode
<
T
>(
key
,
range
.
start
,
range
.
end
));
...
...
@@ -93,6 +93,16 @@ class IntervalTreeNode<T> {
IntervalTreeNode
(
this
.
value
,
this
.
low
,
this
.
high
)
:
computedHigh
=
high
;
Iterable
<
T
>
enumerateAllElements
()
sync
*
{
if
(
left
!=
null
)
{
yield
*
left
!.
enumerateAllElements
();
}
yield
value
;
if
(
right
!=
null
)
{
yield
*
right
!.
enumerateAllElements
();
}
}
bool
contains
(
int
x
)
{
return
low
<=
x
&&
x
<=
high
;
}
...
...
lib/web_ui/lib/src/engine/canvaskit/text.dart
浏览文件 @
bcd8c715
...
...
@@ -714,7 +714,7 @@ class CkParagraphBuilder implements ui.ParagraphBuilder {
missingCodeUnits
.
add
(
codeUnits
[
i
]);
}
}
_
findFontsForMissingCodeunits
(
missingCodeUnits
);
findFontsForMissingCodeunits
(
missingCodeUnits
);
}
}
...
...
lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart
浏览文件 @
bcd8c715
...
...
@@ -4,6 +4,7 @@
// @dart = 2.12
import
'dart:async'
;
import
'dart:math'
as
math
;
import
'dart:typed_data'
;
import
'package:ui/ui.dart'
as
ui
;
...
...
@@ -206,6 +207,116 @@ void testMain() {
expect
(
notoDownloadQueue
.
isPending
,
isFalse
);
expect
(
skiaFontCollection
.
globalFontFallbacks
,
[
'Roboto'
]);
});
// Regression test for https://github.com/flutter/flutter/issues/75836
// When we had this bug our font fallback resolution logic would end up in an
// infinite loop and this test would freeze and time out.
test
(
'Can find fonts for two adjacent unmatched code units from different fonts'
,
()
async
{
final
LoggingDownloader
loggingDownloader
=
LoggingDownloader
(
NotoDownloader
());
notoDownloadQueue
.
downloader
=
loggingDownloader
;
// Try rendering text that requires fallback fonts, initially before the fonts are loaded.
CkParagraphBuilder
(
CkParagraphStyle
()).
addText
(
'ヽಠ'
);
await
notoDownloadQueue
.
downloader
.
debugWhenIdle
();
expect
(
loggingDownloader
.
log
,
<
String
>[
'https://fonts.googleapis.com/css2?family=Noto+Sans+SC'
,
'https://fonts.googleapis.com/css2?family=Noto+Sans+Kannada+UI'
,
'Noto Sans SC'
,
'Noto Sans Kannada UI'
,
],
);
// Do the same thing but this time with loaded fonts.
loggingDownloader
.
log
.
clear
();
CkParagraphBuilder
(
CkParagraphStyle
()).
addText
(
'ヽಠ'
);
await
notoDownloadQueue
.
downloader
.
debugWhenIdle
();
expect
(
loggingDownloader
.
log
,
isEmpty
);
});
test
(
'findMinimumFontsForCodeunits for all supported code units'
,
()
async
{
final
LoggingDownloader
loggingDownloader
=
LoggingDownloader
(
NotoDownloader
());
notoDownloadQueue
.
downloader
=
loggingDownloader
;
// Collect all supported code units from all fallback fonts in the Noto
// font tree.
final
Set
<
String
>
testedFonts
=
<
String
>{};
final
Set
<
int
>
supportedUniqueCodeUnits
=
<
int
>{};
for
(
NotoFont
font
in
debugNotoTree
.
root
.
enumerateAllElements
())
{
testedFonts
.
add
(
font
.
name
);
for
(
CodeunitRange
range
in
font
.
unicodeRanges
)
{
for
(
int
codeUnit
=
range
.
start
;
codeUnit
<
range
.
end
;
codeUnit
+=
1
)
{
supportedUniqueCodeUnits
.
add
(
codeUnit
);
}
}
}
expect
(
supportedUniqueCodeUnits
.
length
,
greaterThan
(
10000
));
// sanity check
expect
(
testedFonts
,
unorderedEquals
(<
String
>{
'Noto Sans'
,
'Noto Sans Malayalam UI'
,
'Noto Sans Armenian'
,
'Noto Sans Georgian'
,
'Noto Sans Hebrew'
,
'Noto Naskh Arabic UI'
,
'Noto Sans Devanagari UI'
,
'Noto Sans Telugu UI'
,
'Noto Sans Tamil UI'
,
'Noto Sans Kannada UI'
,
'Noto Sans Sinhala'
,
'Noto Sans Gurmukhi UI'
,
'Noto Sans Gujarati UI'
,
'Noto Sans Bengali UI'
,
'Noto Sans Thai UI'
,
'Noto Sans Lao UI'
,
'Noto Sans Myanmar UI'
,
'Noto Sans Ethiopic'
,
'Noto Sans Khmer UI'
,
'Noto Sans SC'
,
'Noto Sans JP'
,
'Noto Sans TC'
,
'Noto Sans HK'
,
'Noto Sans KR'
,
'Noto Sans Egyptian Hieroglyphs'
,
}));
// Construct random paragraphs out of supported code units.
final
math
.
Random
random
=
math
.
Random
(
0
);
final
List
<
int
>
supportedCodeUnits
=
supportedUniqueCodeUnits
.
toList
()..
shuffle
(
random
);
const
int
paragraphLength
=
3
;
for
(
int
batchStart
=
0
;
batchStart
<
supportedCodeUnits
.
length
;
batchStart
+=
paragraphLength
)
{
final
int
batchEnd
=
math
.
min
(
batchStart
+
paragraphLength
,
supportedCodeUnits
.
length
);
final
List
<
int
>
codeUnits
=
<
int
>[];
for
(
int
i
=
batchStart
;
i
<
batchEnd
;
i
+=
1
)
{
codeUnits
.
add
(
supportedCodeUnits
[
i
]);
}
final
Set
<
NotoFont
>
fonts
=
<
NotoFont
>{};
for
(
int
codeunit
in
codeUnits
)
{
List
<
NotoFont
>
fontsForUnit
=
debugNotoTree
.
intersections
(
codeunit
);
// All code units are extracted from the same tree, so there must
// be at least one font supporting each code unit
expect
(
fontsForUnit
,
isNotEmpty
);
// Make sure that every returned font indeed covers the code unit.
expect
(
fontsForUnit
.
every
((
font
)
=>
font
.
matchesCodeunit
(
codeunit
)),
isTrue
);
fonts
.
addAll
(
fontsForUnit
);
}
try
{
findMinimumFontsForCodeunits
(
codeUnits
,
fonts
);
}
catch
(
e
)
{
print
(
'findMinimumFontsForCodeunits failed:
\n
'
' Code units:
${codeUnits.join(', ')}
\n
'
' Fonts:
${fonts.map((f) => f.name).join(', ')}
'
,
);
rethrow
;
}
}
});
// TODO: https://github.com/flutter/flutter/issues/60040
},
skip:
isIosSafari
);
}
...
...
@@ -213,7 +324,7 @@ void testMain() {
class
TestDownloader
extends
NotoDownloader
{
static
final
Map
<
String
,
String
>
mockDownloads
=
<
String
,
String
>{};
@override
Future
<
String
>
downloadAsString
(
String
url
)
async
{
Future
<
String
>
downloadAsString
(
String
url
,
{
String
?
debugDescription
}
)
async
{
if
(
mockDownloads
.
containsKey
(
url
))
{
return
mockDownloads
[
url
]!;
}
else
{
...
...
@@ -221,3 +332,28 @@ class TestDownloader extends NotoDownloader {
}
}
}
class
LoggingDownloader
implements
NotoDownloader
{
final
List
<
String
>
log
=
<
String
>[];
LoggingDownloader
(
this
.
delegate
);
final
NotoDownloader
delegate
;
@override
Future
<
void
>
debugWhenIdle
()
{
return
delegate
.
debugWhenIdle
();
}
@override
Future
<
ByteBuffer
>
downloadAsBytes
(
String
url
,
{
String
?
debugDescription
})
{
log
.
add
(
debugDescription
??
url
);
return
delegate
.
downloadAsBytes
(
url
);
}
@override
Future
<
String
>
downloadAsString
(
String
url
,
{
String
?
debugDescription
})
{
log
.
add
(
debugDescription
??
url
);
return
delegate
.
downloadAsString
(
url
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录