Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
weixin_43355755
engine
提交
89a46af1
E
engine
项目概览
weixin_43355755
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
89a46af1
编写于
10月 02, 2020
作者:
D
Dan Field
提交者:
GitHub
10月 02, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement Image.clone for CanvasKit (#21555)
上级
2d42c165
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
168 addition
and
20 deletion
+168
-20
lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
+4
-0
lib/web_ui/lib/src/engine/canvaskit/image.dart
lib/web_ui/lib/src/engine/canvaskit/image.dart
+31
-10
lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart
lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart
+49
-9
lib/web_ui/test/canvaskit/image_test.dart
lib/web_ui/test/canvaskit/image_test.dart
+42
-0
lib/web_ui/test/canvaskit/skia_objects_cache_test.dart
lib/web_ui/test/canvaskit/skia_objects_cache_test.dart
+42
-1
未找到文件。
lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
浏览文件 @
89a46af1
...
@@ -683,6 +683,8 @@ class SkAnimatedImage {
...
@@ -683,6 +683,8 @@ class SkAnimatedImage {
///
///
/// This object is no longer usable after calling this method.
/// This object is no longer usable after calling this method.
external
void
delete
();
external
void
delete
();
external
bool
isAliasOf
(
SkAnimatedImage
other
);
external
bool
isDeleted
();
}
}
@JS
()
@JS
()
...
@@ -698,6 +700,8 @@ class SkImage {
...
@@ -698,6 +700,8 @@ class SkImage {
);
);
external
Uint8List
readPixels
(
SkImageInfo
imageInfo
,
int
srcX
,
int
srcY
);
external
Uint8List
readPixels
(
SkImageInfo
imageInfo
,
int
srcX
,
int
srcY
);
external
SkData
encodeToData
();
external
SkData
encodeToData
();
external
bool
isAliasOf
(
SkImage
other
);
external
bool
isDeleted
();
}
}
@JS
()
@JS
()
...
...
lib/web_ui/lib/src/engine/canvaskit/image.dart
浏览文件 @
89a46af1
...
@@ -43,8 +43,15 @@ class CkAnimatedImage implements ui.Image {
...
@@ -43,8 +43,15 @@ class CkAnimatedImage implements ui.Image {
// being garbage-collected, or by an explicit call to [delete].
// being garbage-collected, or by an explicit call to [delete].
late
final
SkiaObjectBox
box
;
late
final
SkiaObjectBox
box
;
CkAnimatedImage
(
this
.
_skAnimatedImage
)
{
CkAnimatedImage
(
SkAnimatedImage
skAnimatedImage
)
:
this
.
_
(
skAnimatedImage
,
null
);
box
=
SkiaObjectBox
(
this
,
_skAnimatedImage
as
SkDeletable
);
CkAnimatedImage
.
_
(
this
.
_skAnimatedImage
,
SkiaObjectBox
?
boxToClone
)
{
if
(
boxToClone
!=
null
)
{
assert
(
boxToClone
.
skObject
==
_skAnimatedImage
);
box
=
boxToClone
.
clone
(
this
);
}
else
{
box
=
SkiaObjectBox
(
this
,
_skAnimatedImage
as
SkDeletable
);
}
}
}
@override
@override
...
@@ -53,13 +60,17 @@ class CkAnimatedImage implements ui.Image {
...
@@ -53,13 +60,17 @@ class CkAnimatedImage implements ui.Image {
}
}
@override
@override
ui
.
Image
clone
()
=>
this
;
ui
.
Image
clone
()
=>
CkAnimatedImage
.
_
(
_skAnimatedImage
,
box
)
;
@override
@override
bool
isCloneOf
(
ui
.
Image
other
)
=>
other
==
this
;
bool
isCloneOf
(
ui
.
Image
other
)
{
return
other
is
CkAnimatedImage
&&
other
.
_skAnimatedImage
.
isAliasOf
(
_skAnimatedImage
);
}
@override
@override
List
<
StackTrace
>?
debugGetOpenHandleStackTraces
()
=>
null
;
List
<
StackTrace
>?
debugGetOpenHandleStackTraces
()
=>
box
.
debugGetStackTraces
();
int
get
frameCount
=>
_skAnimatedImage
.
getFrameCount
();
int
get
frameCount
=>
_skAnimatedImage
.
getFrameCount
();
/// Decodes the next frame and returns the frame duration.
/// Decodes the next frame and returns the frame duration.
...
@@ -116,8 +127,15 @@ class CkImage implements ui.Image {
...
@@ -116,8 +127,15 @@ class CkImage implements ui.Image {
// being garbage-collected, or by an explicit call to [delete].
// being garbage-collected, or by an explicit call to [delete].
late
final
SkiaObjectBox
box
;
late
final
SkiaObjectBox
box
;
CkImage
(
this
.
skImage
)
{
CkImage
(
SkImage
skImage
)
:
this
.
_
(
skImage
,
null
);
box
=
SkiaObjectBox
(
this
,
skImage
as
SkDeletable
);
CkImage
.
_
(
this
.
skImage
,
SkiaObjectBox
?
boxToClone
)
{
if
(
boxToClone
!=
null
)
{
assert
(
boxToClone
.
skObject
==
skImage
);
box
=
boxToClone
.
clone
(
this
);
}
else
{
box
=
SkiaObjectBox
(
this
,
skImage
as
SkDeletable
);
}
}
}
@override
@override
...
@@ -126,13 +144,16 @@ class CkImage implements ui.Image {
...
@@ -126,13 +144,16 @@ class CkImage implements ui.Image {
}
}
@override
@override
ui
.
Image
clone
()
=>
this
;
ui
.
Image
clone
()
=>
CkImage
.
_
(
skImage
,
box
)
;
@override
@override
bool
isCloneOf
(
ui
.
Image
other
)
=>
other
==
this
;
bool
isCloneOf
(
ui
.
Image
other
)
{
return
other
is
CkImage
&&
other
.
skImage
.
isAliasOf
(
skImage
);
}
@override
@override
List
<
StackTrace
>?
debugGetOpenHandleStackTraces
()
=>
null
;
List
<
StackTrace
>?
debugGetOpenHandleStackTraces
()
=>
box
.
debugGetStackTraces
()
;
@override
@override
int
get
width
=>
skImage
.
width
();
int
get
width
=>
skImage
.
width
();
...
...
lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart
浏览文件 @
89a46af1
...
@@ -239,23 +239,46 @@ abstract class OneShotSkiaObject<T extends Object> extends SkiaObject<T> {
...
@@ -239,23 +239,46 @@ abstract class OneShotSkiaObject<T extends Object> extends SkiaObject<T> {
}
}
}
}
/// Manages the lifecycle of a Skia object owned by a wrapper object.
/// Uses reference counting to manage the lifecycle of a Skia object owned by a
/// wrapper object.
///
///
/// When the wrapper is garbage collected, de
letes the corresponding
/// When the wrapper is garbage collected, de
crements the refcount (only in
///
[skObject] (only in
browsers that support weak references).
/// browsers that support weak references).
///
///
/// The [delete] method can be used to eagerly de
lete the [skObject]
/// The [delete] method can be used to eagerly de
crement the refcount before the
///
before the
wrapper is garbage collected.
/// wrapper is garbage collected.
///
///
/// The [delete] method may be called any number of times. The box
/// The [delete] method may be called any number of times. The box
/// will only delete the object once.
/// will only delete the object once.
class
SkiaObjectBox
{
class
SkiaObjectBox
{
SkiaObjectBox
(
Object
wrapper
,
this
.
skObject
)
{
SkiaObjectBox
(
Object
wrapper
,
SkDeletable
skObject
)
:
this
.
_
(
wrapper
,
skObject
,
<
SkiaObjectBox
>{});
SkiaObjectBox
.
_
(
Object
wrapper
,
this
.
skObject
,
this
.
_refs
)
{
if
(
assertionsEnabled
)
{
_debugStackTrace
=
StackTrace
.
current
;
}
_refs
.
add
(
this
);
if
(
browserSupportsFinalizationRegistry
)
{
if
(
browserSupportsFinalizationRegistry
)
{
boxRegistry
.
register
(
wrapper
,
this
);
boxRegistry
.
register
(
wrapper
,
this
);
}
}
}
}
/// Reference handles to the same underlying [skObject].
final
Set
<
SkiaObjectBox
>
_refs
;
late
final
StackTrace
?
_debugStackTrace
;
/// If asserts are enabled, the [StackTrace]s representing when a reference
/// was created.
List
<
StackTrace
>?
debugGetStackTraces
()
{
if
(
assertionsEnabled
)
{
return
_refs
.
map
<
StackTrace
>((
SkiaObjectBox
box
)
=>
box
.
_debugStackTrace
!)
.
toList
();
}
return
null
;
}
/// The Skia object whose lifecycle is being managed.
/// The Skia object whose lifecycle is being managed.
final
SkDeletable
skObject
;
final
SkDeletable
skObject
;
...
@@ -269,16 +292,33 @@ class SkiaObjectBox {
...
@@ -269,16 +292,33 @@ class SkiaObjectBox {
box
.
delete
();
box
.
delete
();
}));
}));
/// Deletes the [skObject].
/// Returns a clone of this object, which increases its reference count.
///
/// Clones must be [dispose]d when finished.
SkiaObjectBox
clone
(
Object
wrapper
)
{
assert
(!
_isDeleted
,
'Cannot clone from a deleted handle.'
);
assert
(
_refs
.
isNotEmpty
);
return
SkiaObjectBox
.
_
(
wrapper
,
skObject
,
_refs
);
}
/// Decrements the reference count for the [skObject].
///
///
/// Does nothing if the object has already been deleted.
/// Does nothing if the object has already been deleted.
///
/// If this causes the reference count to drop to zero, deletes the
/// [skObject].
void
delete
()
{
void
delete
()
{
if
(
_isDeleted
)
{
if
(
_isDeleted
)
{
assert
(!
_refs
.
contains
(
this
));
return
;
return
;
}
}
final
bool
removed
=
_refs
.
remove
(
this
);
assert
(
removed
);
_isDeleted
=
true
;
_isDeleted
=
true
;
_skObjectDeleteQueue
.
add
(
skObject
);
if
(
_refs
.
isEmpty
)
{
_skObjectCollector
??=
_scheduleSkObjectCollection
();
_skObjectDeleteQueue
.
add
(
skObject
);
_skObjectCollector
??=
_scheduleSkObjectCollection
();
}
}
}
}
}
...
...
lib/web_ui/test/canvaskit/image_test.dart
浏览文件 @
89a46af1
...
@@ -38,6 +38,27 @@ void testMain() {
...
@@ -38,6 +38,27 @@ void testMain() {
expect
(
image
.
box
.
isDeleted
,
true
);
expect
(
image
.
box
.
isDeleted
,
true
);
});
});
test
(
'CkAnimatedImage can be cloned and explicitly disposed of'
,
()
async
{
final
SkAnimatedImage
skAnimatedImage
=
canvasKit
.
MakeAnimatedImageFromEncoded
(
kTransparentImage
);
final
CkAnimatedImage
image
=
CkAnimatedImage
(
skAnimatedImage
);
final
CkAnimatedImage
imageClone
=
image
.
clone
();
expect
(
image
.
isCloneOf
(
imageClone
),
true
);
expect
(
image
.
box
.
isDeleted
,
false
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
skAnimatedImage
.
isDeleted
(),
false
);
image
.
dispose
();
expect
(
image
.
box
.
isDeleted
,
true
);
expect
(
imageClone
.
box
.
isDeleted
,
false
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
skAnimatedImage
.
isDeleted
(),
false
);
imageClone
.
dispose
();
expect
(
image
.
box
.
isDeleted
,
true
);
expect
(
imageClone
.
box
.
isDeleted
,
true
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
skAnimatedImage
.
isDeleted
(),
true
);
});
test
(
'CkImage toString'
,
()
{
test
(
'CkImage toString'
,
()
{
final
SkImage
skImage
=
canvasKit
.
MakeAnimatedImageFromEncoded
(
kTransparentImage
).
getCurrentFrame
();
final
SkImage
skImage
=
canvasKit
.
MakeAnimatedImageFromEncoded
(
kTransparentImage
).
getCurrentFrame
();
final
CkImage
image
=
CkImage
(
skImage
);
final
CkImage
image
=
CkImage
(
skImage
);
...
@@ -54,6 +75,27 @@ void testMain() {
...
@@ -54,6 +75,27 @@ void testMain() {
image
.
dispose
();
image
.
dispose
();
expect
(
image
.
box
.
isDeleted
,
true
);
expect
(
image
.
box
.
isDeleted
,
true
);
});
});
test
(
'CkImage can be explicitly disposed of when cloned'
,
()
async
{
final
SkImage
skImage
=
canvasKit
.
MakeAnimatedImageFromEncoded
(
kTransparentImage
).
getCurrentFrame
();
final
CkImage
image
=
CkImage
(
skImage
);
final
CkImage
imageClone
=
image
.
clone
();
expect
(
image
.
isCloneOf
(
imageClone
),
true
);
expect
(
image
.
box
.
isDeleted
,
false
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
skImage
.
isDeleted
(),
false
);
image
.
dispose
();
expect
(
image
.
box
.
isDeleted
,
true
);
expect
(
imageClone
.
box
.
isDeleted
,
false
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
skImage
.
isDeleted
(),
false
);
imageClone
.
dispose
();
expect
(
image
.
box
.
isDeleted
,
true
);
expect
(
imageClone
.
box
.
isDeleted
,
true
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
skImage
.
isDeleted
(),
true
);
});
// TODO: https://github.com/flutter/flutter/issues/60040
// TODO: https://github.com/flutter/flutter/issues/60040
},
skip:
isIosSafari
);
},
skip:
isIosSafari
);
}
}
lib/web_ui/test/canvaskit/skia_objects_cache_test.dart
浏览文件 @
89a46af1
...
@@ -12,6 +12,7 @@ import 'package:ui/ui.dart' as ui;
...
@@ -12,6 +12,7 @@ import 'package:ui/ui.dart' as ui;
import
'package:ui/src/engine.dart'
;
import
'package:ui/src/engine.dart'
;
import
'common.dart'
;
import
'common.dart'
;
import
'../matchers.dart'
;
void
main
(
)
{
void
main
(
)
{
internalBootstrapBrowserTest
(()
=>
testMain
);
internalBootstrapBrowserTest
(()
=>
testMain
);
...
@@ -153,9 +154,49 @@ void _tests() {
...
@@ -153,9 +154,49 @@ void _tests() {
expect
(
SkiaObjects
.
oneShotCache
.
debugContains
(
object2
),
isFalse
);
expect
(
SkiaObjects
.
oneShotCache
.
debugContains
(
object2
),
isFalse
);
});
});
});
});
group
(
SkiaObjectBox
,
()
{
test
(
'Records stack traces and respects refcounts'
,
()
async
{
TestOneShotSkiaObject
.
deleteCount
=
0
;
final
TestOneShotSkiaObject
skObject
=
TestOneShotSkiaObject
();
final
Object
wrapper
=
Object
();
final
SkiaObjectBox
box
=
SkiaObjectBox
(
wrapper
,
skObject
);
expect
(
box
.
debugGetStackTraces
().
length
,
1
);
final
SkiaObjectBox
clone
=
box
.
clone
(
wrapper
);
expect
(
clone
,
isNot
(
same
(
box
)));
expect
(
clone
.
debugGetStackTraces
().
length
,
2
);
expect
(
box
.
debugGetStackTraces
().
length
,
2
);
box
.
delete
();
expect
(()
=>
box
.
clone
(
wrapper
),
throwsAssertionError
);
expect
(
box
.
isDeleted
,
true
);
// Let any timers elapse.
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
TestOneShotSkiaObject
.
deleteCount
,
0
);
expect
(
clone
.
debugGetStackTraces
().
length
,
1
);
expect
(
box
.
debugGetStackTraces
().
length
,
1
);
clone
.
delete
();
expect
(()
=>
clone
.
clone
(
wrapper
),
throwsAssertionError
);
// Let any timers elapse.
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
TestOneShotSkiaObject
.
deleteCount
,
1
);
expect
(
clone
.
debugGetStackTraces
().
length
,
0
);
expect
(
box
.
debugGetStackTraces
().
length
,
0
);
});
});
}
}
class
TestOneShotSkiaObject
extends
OneShotSkiaObject
<
SkPaint
>
{
class
TestOneShotSkiaObject
extends
OneShotSkiaObject
<
SkPaint
>
implements
SkDeletable
{
static
int
deleteCount
=
0
;
static
int
deleteCount
=
0
;
TestOneShotSkiaObject
()
:
super
(
SkPaint
());
TestOneShotSkiaObject
()
:
super
(
SkPaint
());
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录