Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
weixin_43355755
engine
提交
ebb5b909
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,发现更多精彩内容 >>
未验证
提交
ebb5b909
编写于
6月 25, 2019
作者:
C
Chris Yang
提交者:
GitHub
6月 25, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
IOS Platform view transform/clipping (#9075)
上级
13145e90
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
728 addition
and
23 deletion
+728
-23
ci/licenses_golden/licenses_flutter
ci/licenses_golden/licenses_flutter
+1
-0
flow/BUILD.gn
flow/BUILD.gn
+1
-0
flow/embedded_views.cc
flow/embedded_views.cc
+30
-0
flow/embedded_views.h
flow/embedded_views.h
+156
-2
flow/layers/clip_rect_layer.cc
flow/layers/clip_rect_layer.cc
+3
-0
flow/layers/clip_rrect_layer.cc
flow/layers/clip_rrect_layer.cc
+3
-0
flow/layers/layer.h
flow/layers/layer.h
+1
-0
flow/layers/layer_tree.cc
flow/layers/layer_tree.cc
+4
-0
flow/layers/performance_overlay_layer_unittests.cc
flow/layers/performance_overlay_layer_unittests.cc
+6
-3
flow/layers/platform_view_layer.cc
flow/layers/platform_view_layer.cc
+1
-0
flow/layers/transform_layer.cc
flow/layers/transform_layer.cc
+3
-0
flow/mutators_stack_unittests.cc
flow/mutators_stack_unittests.cc
+180
-0
flow/raster_cache.cc
flow/raster_cache.cc
+2
-0
shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
...tform/darwin/ios/framework/Source/FlutterPlatformViews.mm
+133
-18
shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
...rwin/ios/framework/Source/FlutterPlatformViews_Internal.h
+64
-0
shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
...win/ios/framework/Source/FlutterPlatformViews_Internal.mm
+140
-0
未找到文件。
ci/licenses_golden/licenses_flutter
浏览文件 @
ebb5b909
...
...
@@ -71,6 +71,7 @@ FILE: ../../../flutter/flow/layers/transform_layer.h
FILE: ../../../flutter/flow/matrix_decomposition.cc
FILE: ../../../flutter/flow/matrix_decomposition.h
FILE: ../../../flutter/flow/matrix_decomposition_unittests.cc
FILE: ../../../flutter/flow/mutators_stack_unittests.cc
FILE: ../../../flutter/flow/paint_utils.cc
FILE: ../../../flutter/flow/paint_utils.h
FILE: ../../../flutter/flow/raster_cache.cc
...
...
flow/BUILD.gn
浏览文件 @
ebb5b909
...
...
@@ -114,6 +114,7 @@ executable("flow_unittests") {
"layers/performance_overlay_layer_unittests.cc",
"layers/physical_shape_layer_unittests.cc",
"matrix_decomposition_unittests.cc",
"mutators_stack_unittests.cc",
"raster_cache_unittests.cc",
]
...
...
flow/embedded_views.cc
浏览文件 @
ebb5b909
...
...
@@ -9,4 +9,34 @@ namespace flutter {
bool
ExternalViewEmbedder
::
SubmitFrame
(
GrContext
*
context
)
{
return
false
;
};
void
MutatorsStack
::
pushClipRect
(
const
SkRect
&
rect
)
{
std
::
shared_ptr
<
Mutator
>
element
=
std
::
make_shared
<
Mutator
>
(
rect
);
vector_
.
push_back
(
element
);
};
void
MutatorsStack
::
pushClipRRect
(
const
SkRRect
&
rrect
)
{
std
::
shared_ptr
<
Mutator
>
element
=
std
::
make_shared
<
Mutator
>
(
rrect
);
vector_
.
push_back
(
element
);
};
void
MutatorsStack
::
pushTransform
(
const
SkMatrix
&
matrix
)
{
std
::
shared_ptr
<
Mutator
>
element
=
std
::
make_shared
<
Mutator
>
(
matrix
);
vector_
.
push_back
(
element
);
};
void
MutatorsStack
::
pop
()
{
vector_
.
pop_back
();
};
const
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>::
const_reverse_iterator
MutatorsStack
::
top
()
const
{
return
vector_
.
rend
();
};
const
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>::
const_reverse_iterator
MutatorsStack
::
bottom
()
const
{
return
vector_
.
rbegin
();
};
}
// namespace flutter
flow/embedded_views.h
浏览文件 @
ebb5b909
...
...
@@ -9,18 +9,169 @@
#include "flutter/fml/memory/ref_counted.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSize.h"
namespace
flutter
{
enum
MutatorType
{
clip_rect
,
clip_rrect
,
clip_path
,
transform
};
// Stores mutation information like clipping or transform.
//
// The `type` indicates the type of the mutation: clip_rect, transform and etc.
// Each `type` is paired with an object that supports the mutation. For example,
// if the `type` is clip_rect, `rect()` is used the represent the rect to be
// clipped. One mutation object must only contain one type of mutation.
class
Mutator
{
public:
Mutator
(
const
Mutator
&
other
)
{
type_
=
other
.
type_
;
switch
(
other
.
type_
)
{
case
clip_rect
:
rect_
=
other
.
rect_
;
break
;
case
clip_rrect
:
rrect_
=
other
.
rrect_
;
break
;
case
clip_path
:
path_
=
new
SkPath
(
*
other
.
path_
);
break
;
case
transform
:
matrix_
=
other
.
matrix_
;
break
;
default:
break
;
}
}
explicit
Mutator
(
const
SkRect
&
rect
)
:
type_
(
clip_rect
),
rect_
(
rect
)
{}
explicit
Mutator
(
const
SkRRect
&
rrect
)
:
type_
(
clip_rrect
),
rrect_
(
rrect
)
{}
explicit
Mutator
(
const
SkPath
&
path
)
:
type_
(
clip_path
),
path_
(
new
SkPath
(
path
))
{}
explicit
Mutator
(
const
SkMatrix
&
matrix
)
:
type_
(
transform
),
matrix_
(
matrix
)
{}
const
MutatorType
&
type
()
const
{
return
type_
;
}
const
SkRect
&
rect
()
const
{
return
rect_
;
}
const
SkRRect
&
rrect
()
const
{
return
rrect_
;
}
const
SkPath
&
path
()
const
{
return
*
path_
;
}
const
SkMatrix
&
matrix
()
const
{
return
matrix_
;
}
bool
operator
==
(
const
Mutator
&
other
)
const
{
if
(
type_
!=
other
.
type_
)
{
return
false
;
}
if
(
type_
==
clip_rect
&&
rect_
==
other
.
rect_
)
{
return
true
;
}
if
(
type_
==
clip_rrect
&&
rrect_
==
other
.
rrect_
)
{
return
true
;
}
if
(
type_
==
clip_path
&&
*
path_
==
*
other
.
path_
)
{
return
true
;
}
if
(
type_
==
transform
&&
matrix_
==
other
.
matrix_
)
{
return
true
;
}
return
false
;
}
bool
operator
!=
(
const
Mutator
&
other
)
const
{
return
!
operator
==
(
other
);
}
bool
isClipType
()
{
return
type_
==
clip_rect
||
type_
==
clip_rrect
||
type_
==
clip_path
;
}
~
Mutator
()
{
if
(
type_
==
clip_path
)
{
delete
path_
;
}
};
private:
MutatorType
type_
;
union
{
SkRect
rect_
;
SkRRect
rrect_
;
SkMatrix
matrix_
;
SkPath
*
path_
;
};
};
// Mutator
// A stack of mutators that can be applied to an embedded platform view.
//
// The stack may include mutators like transforms and clips, each mutator
// applies to all the mutators that are below it in the stack and to the
// embedded view.
//
// For example consider the following stack: [T1, T2, T3], where T1 is the top
// of the stack and T3 is the bottom of the stack. Applying this mutators stack
// to a platform view P1 will result in T1(T2(T2(P1))).
class
MutatorsStack
{
public:
MutatorsStack
()
=
default
;
void
pushClipRect
(
const
SkRect
&
rect
);
void
pushClipRRect
(
const
SkRRect
&
rrect
);
void
pushClipPath
(
const
SkPath
&
path
);
void
pushTransform
(
const
SkMatrix
&
matrix
);
// Removes the `Mutator` on the top of the stack
// and destroys it.
void
pop
();
// Returns an iterator pointing to the top of the stack.
const
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>::
const_reverse_iterator
top
()
const
;
// Returns an iterator pointing to the bottom of the stack.
const
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>::
const_reverse_iterator
bottom
()
const
;
bool
operator
==
(
const
MutatorsStack
&
other
)
const
{
if
(
vector_
.
size
()
!=
other
.
vector_
.
size
())
{
return
false
;
}
for
(
size_t
i
=
0
;
i
<
vector_
.
size
();
i
++
)
{
if
(
*
vector_
[
i
]
!=
*
other
.
vector_
[
i
])
{
return
false
;
}
}
return
true
;
}
bool
operator
!=
(
const
MutatorsStack
&
other
)
const
{
return
!
operator
==
(
other
);
}
private:
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>
vector_
;
};
// MutatorsStack
class
EmbeddedViewParams
{
public:
EmbeddedViewParams
()
=
default
;
EmbeddedViewParams
(
const
EmbeddedViewParams
&
other
)
{
offsetPixels
=
other
.
offsetPixels
;
sizePoints
=
other
.
sizePoints
;
mutatorsStack
=
other
.
mutatorsStack
;
};
SkPoint
offsetPixels
;
SkSize
sizePoints
;
MutatorsStack
mutatorsStack
;
bool
operator
==
(
const
EmbeddedViewParams
&
other
)
const
{
return
offsetPixels
==
other
.
offsetPixels
&&
sizePoints
==
other
.
sizePoints
;
return
offsetPixels
==
other
.
offsetPixels
&&
sizePoints
==
other
.
sizePoints
&&
mutatorsStack
==
other
.
mutatorsStack
;
}
};
...
...
@@ -28,6 +179,8 @@ class EmbeddedViewParams {
// in this case ExternalViewEmbedder is a reference to the
// FlutterPlatformViewsController which is owned by FlutterViewController.
class
ExternalViewEmbedder
{
// TODO(cyanglaz): Make embedder own the `EmbeddedViewParams`.
public:
ExternalViewEmbedder
()
=
default
;
...
...
@@ -46,7 +199,8 @@ class ExternalViewEmbedder {
virtual
~
ExternalViewEmbedder
()
=
default
;
FML_DISALLOW_COPY_AND_ASSIGN
(
ExternalViewEmbedder
);
};
};
// ExternalViewEmbedder
}
// namespace flutter
...
...
flow/layers/clip_rect_layer.cc
浏览文件 @
ebb5b909
...
...
@@ -50,6 +50,8 @@ void ClipRectLayer::Paint(PaintContext& context) const {
SkAutoCanvasRestore
save
(
context
.
internal_nodes_canvas
,
true
);
context
.
internal_nodes_canvas
->
clipRect
(
clip_rect_
,
clip_behavior_
!=
Clip
::
hardEdge
);
context
.
mutators_stack
.
pushClipRect
(
clip_rect_
);
if
(
clip_behavior_
==
Clip
::
antiAliasWithSaveLayer
)
{
context
.
internal_nodes_canvas
->
saveLayer
(
clip_rect_
,
nullptr
);
}
...
...
@@ -57,6 +59,7 @@ void ClipRectLayer::Paint(PaintContext& context) const {
if
(
clip_behavior_
==
Clip
::
antiAliasWithSaveLayer
)
{
context
.
internal_nodes_canvas
->
restore
();
}
context
.
mutators_stack
.
pop
();
}
}
// namespace flutter
flow/layers/clip_rrect_layer.cc
浏览文件 @
ebb5b909
...
...
@@ -58,6 +58,8 @@ void ClipRRectLayer::Paint(PaintContext& context) const {
SkAutoCanvasRestore
save
(
context
.
internal_nodes_canvas
,
true
);
context
.
internal_nodes_canvas
->
clipRRect
(
clip_rrect_
,
clip_behavior_
!=
Clip
::
hardEdge
);
context
.
mutators_stack
.
pushClipRRect
(
clip_rrect_
);
if
(
clip_behavior_
==
Clip
::
antiAliasWithSaveLayer
)
{
context
.
internal_nodes_canvas
->
saveLayer
(
paint_bounds
(),
nullptr
);
}
...
...
@@ -65,6 +67,7 @@ void ClipRRectLayer::Paint(PaintContext& context) const {
if
(
clip_behavior_
==
Clip
::
antiAliasWithSaveLayer
)
{
context
.
internal_nodes_canvas
->
restore
();
}
context
.
mutators_stack
.
pop
();
}
}
// namespace flutter
flow/layers/layer.h
浏览文件 @
ebb5b909
...
...
@@ -83,6 +83,7 @@ class Layer {
SkCanvas
*
leaf_nodes_canvas
;
GrContext
*
gr_context
;
ExternalViewEmbedder
*
view_embedder
;
MutatorsStack
&
mutators_stack
;
const
Stopwatch
&
raster_time
;
const
Stopwatch
&
ui_time
;
TextureRegistry
&
texture_registry
;
...
...
flow/layers/layer_tree.cc
浏览文件 @
ebb5b909
...
...
@@ -83,11 +83,13 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
}
}
MutatorsStack
stack
;
Layer
::
PaintContext
context
=
{
(
SkCanvas
*
)
&
internal_nodes_canvas
,
frame
.
canvas
(),
frame
.
gr_context
(),
frame
.
view_embedder
(),
stack
,
frame
.
context
().
raster_time
(),
frame
.
context
().
ui_time
(),
frame
.
context
().
texture_registry
(),
...
...
@@ -108,6 +110,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
return
nullptr
;
}
MutatorsStack
unused_stack
;
const
Stopwatch
unused_stopwatch
;
TextureRegistry
unused_texture_registry
;
SkMatrix
root_surface_transformation
;
...
...
@@ -135,6 +138,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
canvas
,
// canvas
nullptr
,
nullptr
,
unused_stack
,
unused_stopwatch
,
// frame time (dont care)
unused_stopwatch
,
// engine time (dont care)
unused_texture_registry
,
// texture registry (not supported)
...
...
flow/layers/performance_overlay_layer_unittests.cc
浏览文件 @
ebb5b909
...
...
@@ -47,10 +47,13 @@ TEST(PerformanceOverlayLayer, Gold) {
ASSERT_TRUE
(
surface
!=
nullptr
);
flutter
::
TextureRegistry
unused_texture_registry
;
flutter
::
MutatorsStack
unused_stack
;
flutter
::
Layer
::
PaintContext
paintContext
=
{
nullptr
,
surface
->
getCanvas
(),
nullptr
,
nullptr
,
mock_stopwatch
,
mock_stopwatch
,
unused_texture_registry
,
nullptr
,
false
};
nullptr
,
surface
->
getCanvas
(),
nullptr
,
nullptr
,
unused_stack
,
mock_stopwatch
,
mock_stopwatch
,
unused_texture_registry
,
nullptr
,
false
};
// Specify font file to ensure the same font across different operation
// systems.
...
...
flow/layers/platform_view_layer.cc
浏览文件 @
ebb5b909
...
...
@@ -37,6 +37,7 @@ void PlatformViewLayer::Paint(PaintContext& context) const {
params
.
offsetPixels
=
SkPoint
::
Make
(
transform
.
getTranslateX
(),
transform
.
getTranslateY
());
params
.
sizePoints
=
size_
;
params
.
mutatorsStack
=
context
.
mutators_stack
;
SkCanvas
*
canvas
=
context
.
view_embedder
->
CompositeEmbeddedView
(
view_id_
,
params
);
...
...
flow/layers/transform_layer.cc
浏览文件 @
ebb5b909
...
...
@@ -66,7 +66,10 @@ void TransformLayer::Paint(PaintContext& context) const {
SkAutoCanvasRestore
save
(
context
.
internal_nodes_canvas
,
true
);
context
.
internal_nodes_canvas
->
concat
(
transform_
);
context
.
mutators_stack
.
pushTransform
(
transform_
);
PaintChildren
(
context
);
context
.
mutators_stack
.
pop
();
}
}
// namespace flutter
flow/mutators_stack_unittests.cc
0 → 100644
浏览文件 @
ebb5b909
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/flow/embedded_views.h"
#include "gtest/gtest.h"
TEST
(
MutatorsStack
,
Initialization
)
{
flutter
::
MutatorsStack
stack
;
ASSERT_TRUE
(
true
);
}
TEST
(
MutatorsStack
,
CopyConstructor
)
{
flutter
::
MutatorsStack
stack
;
SkRRect
rrect
;
SkRect
rect
;
stack
.
pushClipRect
(
rect
);
stack
.
pushClipRRect
(
rrect
);
flutter
::
MutatorsStack
copy
=
flutter
::
MutatorsStack
(
stack
);
ASSERT_TRUE
(
copy
==
stack
);
}
TEST
(
MutatorsStack
,
PushClipRect
)
{
flutter
::
MutatorsStack
stack
;
SkRect
rect
;
stack
.
pushClipRect
(
rect
);
auto
iter
=
stack
.
bottom
();
ASSERT_TRUE
(
iter
->
get
()
->
type
()
==
flutter
::
MutatorType
::
clip_rect
);
ASSERT_TRUE
(
iter
->
get
()
->
rect
()
==
rect
);
}
TEST
(
MutatorsStack
,
PushClipRRect
)
{
flutter
::
MutatorsStack
stack
;
SkRRect
rrect
;
stack
.
pushClipRRect
(
rrect
);
auto
iter
=
stack
.
bottom
();
ASSERT_TRUE
(
iter
->
get
()
->
type
()
==
flutter
::
MutatorType
::
clip_rrect
);
ASSERT_TRUE
(
iter
->
get
()
->
rrect
()
==
rrect
);
}
TEST
(
MutatorsStack
,
PushTransform
)
{
flutter
::
MutatorsStack
stack
;
SkMatrix
matrix
;
stack
.
pushTransform
(
matrix
);
auto
iter
=
stack
.
bottom
();
ASSERT_TRUE
(
iter
->
get
()
->
type
()
==
flutter
::
MutatorType
::
transform
);
ASSERT_TRUE
(
iter
->
get
()
->
matrix
()
==
matrix
);
}
TEST
(
MutatorsStack
,
Pop
)
{
flutter
::
MutatorsStack
stack
;
SkMatrix
matrix
;
stack
.
pushTransform
(
matrix
);
stack
.
pop
();
auto
iter
=
stack
.
bottom
();
ASSERT_TRUE
(
iter
==
stack
.
top
());
}
TEST
(
MutatorsStack
,
Traversal
)
{
flutter
::
MutatorsStack
stack
;
SkMatrix
matrix
;
stack
.
pushTransform
(
matrix
);
SkRect
rect
;
stack
.
pushClipRect
(
rect
);
SkRRect
rrect
;
stack
.
pushClipRRect
(
rrect
);
auto
iter
=
stack
.
bottom
();
int
index
=
0
;
while
(
iter
!=
stack
.
top
())
{
switch
(
index
)
{
case
0
:
ASSERT_TRUE
(
iter
->
get
()
->
type
()
==
flutter
::
MutatorType
::
clip_rrect
);
ASSERT_TRUE
(
iter
->
get
()
->
rrect
()
==
rrect
);
break
;
case
1
:
ASSERT_TRUE
(
iter
->
get
()
->
type
()
==
flutter
::
MutatorType
::
clip_rect
);
ASSERT_TRUE
(
iter
->
get
()
->
rect
()
==
rect
);
break
;
case
2
:
ASSERT_TRUE
(
iter
->
get
()
->
type
()
==
flutter
::
MutatorType
::
transform
);
ASSERT_TRUE
(
iter
->
get
()
->
matrix
()
==
matrix
);
break
;
default:
break
;
}
++
iter
;
++
index
;
}
}
TEST
(
MutatorsStack
,
Equality
)
{
flutter
::
MutatorsStack
stack
;
SkMatrix
matrix
=
SkMatrix
::
MakeScale
(
1
,
1
);
stack
.
pushTransform
(
matrix
);
SkRect
rect
=
SkRect
::
MakeEmpty
();
stack
.
pushClipRect
(
rect
);
SkRRect
rrect
=
SkRRect
::
MakeEmpty
();
stack
.
pushClipRRect
(
rrect
);
flutter
::
MutatorsStack
stackOther
;
SkMatrix
matrixOther
=
SkMatrix
::
MakeScale
(
1
,
1
);
stackOther
.
pushTransform
(
matrixOther
);
SkRect
rectOther
=
SkRect
::
MakeEmpty
();
stackOther
.
pushClipRect
(
rectOther
);
SkRRect
rrectOther
=
SkRRect
::
MakeEmpty
();
stackOther
.
pushClipRRect
(
rrectOther
);
ASSERT_TRUE
(
stack
==
stackOther
);
}
TEST
(
Mutator
,
Initialization
)
{
SkRect
rect
=
SkRect
::
MakeEmpty
();
flutter
::
Mutator
mutator
=
flutter
::
Mutator
(
rect
);
ASSERT_TRUE
(
mutator
.
type
()
==
flutter
::
MutatorType
::
clip_rect
);
ASSERT_TRUE
(
mutator
.
rect
()
==
rect
);
SkRRect
rrect
;
flutter
::
Mutator
mutator2
=
flutter
::
Mutator
(
rrect
);
ASSERT_TRUE
(
mutator2
.
type
()
==
flutter
::
MutatorType
::
clip_rrect
);
ASSERT_TRUE
(
mutator2
.
rrect
()
==
rrect
);
SkPath
path
;
flutter
::
Mutator
mutator3
=
flutter
::
Mutator
(
path
);
ASSERT_TRUE
(
mutator3
.
type
()
==
flutter
::
MutatorType
::
clip_path
);
ASSERT_TRUE
(
mutator3
.
path
()
==
path
);
SkMatrix
matrix
;
flutter
::
Mutator
mutator4
=
flutter
::
Mutator
(
matrix
);
ASSERT_TRUE
(
mutator4
.
type
()
==
flutter
::
MutatorType
::
transform
);
ASSERT_TRUE
(
mutator4
.
matrix
()
==
matrix
);
}
TEST
(
Mutator
,
CopyConstructor
)
{
SkRect
rect
=
SkRect
::
MakeEmpty
();
flutter
::
Mutator
mutator
=
flutter
::
Mutator
(
rect
);
flutter
::
Mutator
copy
=
flutter
::
Mutator
(
mutator
);
ASSERT_TRUE
(
mutator
==
copy
);
SkRRect
rrect
;
flutter
::
Mutator
mutator2
=
flutter
::
Mutator
(
rrect
);
flutter
::
Mutator
copy2
=
flutter
::
Mutator
(
mutator2
);
ASSERT_TRUE
(
mutator2
==
copy2
);
SkPath
path
;
flutter
::
Mutator
mutator3
=
flutter
::
Mutator
(
path
);
flutter
::
Mutator
copy3
=
flutter
::
Mutator
(
mutator3
);
ASSERT_TRUE
(
mutator3
==
copy3
);
SkMatrix
matrix
;
flutter
::
Mutator
mutator4
=
flutter
::
Mutator
(
matrix
);
flutter
::
Mutator
copy4
=
flutter
::
Mutator
(
mutator4
);
ASSERT_TRUE
(
mutator4
==
copy4
);
}
TEST
(
Mutator
,
Equality
)
{
SkMatrix
matrix
;
flutter
::
Mutator
mutator
=
flutter
::
Mutator
(
matrix
);
flutter
::
Mutator
otherMutator
=
flutter
::
Mutator
(
matrix
);
ASSERT_TRUE
(
mutator
==
otherMutator
);
SkRect
rect
=
SkRect
::
MakeEmpty
();
flutter
::
Mutator
mutator2
=
flutter
::
Mutator
(
rect
);
flutter
::
Mutator
otherMutator2
=
flutter
::
Mutator
(
rect
);
ASSERT_TRUE
(
mutator2
==
otherMutator2
);
SkRRect
rrect
;
flutter
::
Mutator
mutator3
=
flutter
::
Mutator
(
rrect
);
flutter
::
Mutator
otherMutator3
=
flutter
::
Mutator
(
rrect
);
ASSERT_TRUE
(
mutator3
==
otherMutator3
);
ASSERT_FALSE
(
mutator2
==
mutator
);
}
TEST
(
Mutator
,
UnEquality
)
{
SkRect
rect
=
SkRect
::
MakeEmpty
();
flutter
::
Mutator
mutator
=
flutter
::
Mutator
(
rect
);
SkMatrix
matrix
;
flutter
::
Mutator
notEqualMutator
=
flutter
::
Mutator
(
matrix
);
ASSERT_TRUE
(
notEqualMutator
!=
mutator
);
}
flow/raster_cache.cc
浏览文件 @
ebb5b909
...
...
@@ -159,6 +159,7 @@ void RasterCache::Prepare(PrerollContext* context,
entry
.
image
=
Rasterize
(
context
->
gr_context
,
ctm
,
context
->
dst_color_space
,
checkerboard_images_
,
layer
->
paint_bounds
(),
[
layer
,
context
](
SkCanvas
*
canvas
)
{
MutatorsStack
stack
;
SkISize
canvas_size
=
canvas
->
getBaseLayerSize
();
SkNWayCanvas
internal_nodes_canvas
(
canvas_size
.
width
(),
canvas_size
.
height
());
...
...
@@ -168,6 +169,7 @@ void RasterCache::Prepare(PrerollContext* context,
canvas
,
context
->
gr_context
,
nullptr
,
stack
,
context
->
raster_time
,
context
->
ui_time
,
context
->
texture_registry
,
...
...
shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
浏览文件 @
ebb5b909
...
...
@@ -91,6 +91,7 @@ void FlutterPlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterRe
touch_interceptors_
[
viewId
]
=
fml
::
scoped_nsobject
<
FlutterTouchInterceptingView
>
([
touch_interceptor
retain
]);
root_views_
[
viewId
]
=
fml
::
scoped_nsobject
<
UIView
>
([
touch_interceptor
retain
]);
result
(
nil
);
}
...
...
@@ -182,6 +183,117 @@ std::vector<SkCanvas*> FlutterPlatformViewsController::GetCurrentCanvases() {
return
canvases
;
}
int
FlutterPlatformViewsController
::
CountClips
(
const
MutatorsStack
&
mutators_stack
)
{
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>::
const_reverse_iterator
iter
=
mutators_stack
.
bottom
();
int
clipCount
=
0
;
while
(
iter
!=
mutators_stack
.
top
())
{
if
((
*
iter
)
->
isClipType
())
{
clipCount
++
;
}
++
iter
;
}
return
clipCount
;
}
UIView
*
FlutterPlatformViewsController
::
ReconstructClipViewsChain
(
int
number_of_clips
,
UIView
*
platform_view
,
UIView
*
head_clip_view
)
{
NSInteger
indexInFlutterView
=
-
1
;
if
(
head_clip_view
.
superview
)
{
// TODO(cyanglaz): potentially cache the index of oldPlatformViewRoot to make this a O(1).
// https://github.com/flutter/flutter/issues/35023
indexInFlutterView
=
[
flutter_view_
.
get
().
subviews
indexOfObject
:
head_clip_view
];
[
head_clip_view
removeFromSuperview
];
}
UIView
*
head
=
platform_view
;
int
clipIndex
=
0
;
// Re-use as much existing clip views as needed.
while
(
head
!=
head_clip_view
&&
clipIndex
<
number_of_clips
)
{
head
=
head
.
superview
;
clipIndex
++
;
}
// If there were not enough existing clip views, add more.
while
(
clipIndex
<
number_of_clips
)
{
ChildClippingView
*
clippingView
=
[
ChildClippingView
new
];
[
clippingView
addSubview
:
head
];
head
=
clippingView
;
clipIndex
++
;
}
[
head
removeFromSuperview
];
if
(
indexInFlutterView
>
-
1
)
{
// The chain was previously attached; attach it to the same position.
[
flutter_view_
.
get
()
insertSubview
:
head
atIndex
:
indexInFlutterView
];
}
return
head
;
}
void
FlutterPlatformViewsController
::
ApplyMutators
(
const
MutatorsStack
&
mutators_stack
,
UIView
*
embedded_view
)
{
UIView
*
head
=
embedded_view
;
head
.
clipsToBounds
=
YES
;
head
.
layer
.
transform
=
CATransform3DIdentity
;
ResetAnchor
(
head
.
layer
);
std
::
vector
<
std
::
shared_ptr
<
Mutator
>>::
const_reverse_iterator
iter
=
mutators_stack
.
bottom
();
while
(
iter
!=
mutators_stack
.
top
())
{
switch
((
*
iter
)
->
type
())
{
case
transform
:
{
CATransform3D
transform
=
GetCATransform3DFromSkMatrix
((
*
iter
)
->
matrix
());
head
.
layer
.
transform
=
CATransform3DConcat
(
head
.
layer
.
transform
,
transform
);
break
;
}
case
clip_rect
:
case
clip_rrect
:
case
clip_path
:
{
ChildClippingView
*
clipView
=
(
ChildClippingView
*
)
head
.
superview
;
clipView
.
layer
.
transform
=
CATransform3DIdentity
;
[
clipView
setClip
:(
*
iter
)
->
type
()
rect:
(
*
iter
)
->
rect
()
rrect:
(
*
iter
)
->
rrect
()
path:
(
*
iter
)
->
path
()];
head
.
clipsToBounds
=
YES
;
ResetAnchor
(
clipView
.
layer
);
head
=
clipView
;
break
;
}
}
++
iter
;
}
// Reverse scale based on screen scale.
//
// The UIKit frame is set based on the logical resolution instead of physical.
// (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html).
// However, flow is based on the physical resolution. For eaxmple, 1000 pixels in flow equals
// 500 points in UIKit. And until this point, we did all the calculation based on the flow
// resolution. So we need to scale down to match UIKit's logical resolution.
CGFloat
screenScale
=
[
UIScreen
mainScreen
].
scale
;
head
.
layer
.
transform
=
CATransform3DConcat
(
head
.
layer
.
transform
,
CATransform3DMakeScale
(
1
/
screenScale
,
1
/
screenScale
,
1
));
}
void
FlutterPlatformViewsController
::
CompositeWithParams
(
int
view_id
,
const
flutter
::
EmbeddedViewParams
&
params
)
{
CGRect
frame
=
CGRectMake
(
0
,
0
,
params
.
sizePoints
.
width
(),
params
.
sizePoints
.
height
());
UIView
*
touchInterceptor
=
touch_interceptors_
[
view_id
].
get
();
touchInterceptor
.
frame
=
frame
;
int
currentClippingCount
=
CountClips
(
params
.
mutatorsStack
);
int
previousClippingCount
=
clip_count_
[
view_id
];
if
(
currentClippingCount
!=
previousClippingCount
)
{
clip_count_
[
view_id
]
=
currentClippingCount
;
// If we have a different clipping count in this frame, we need to reconstruct the
// ClippingChildView chain to prepare for `ApplyMutators`.
UIView
*
oldPlatformViewRoot
=
root_views_
[
view_id
].
get
();
UIView
*
newPlatformViewRoot
=
ReconstructClipViewsChain
(
currentClippingCount
,
touchInterceptor
,
oldPlatformViewRoot
);
root_views_
[
view_id
]
=
fml
::
scoped_nsobject
<
UIView
>
([
newPlatformViewRoot
retain
]);
}
ApplyMutators
(
params
.
mutatorsStack
,
touchInterceptor
);
}
SkCanvas
*
FlutterPlatformViewsController
::
CompositeEmbeddedView
(
int
view_id
,
const
flutter
::
EmbeddedViewParams
&
params
)
{
...
...
@@ -193,15 +305,8 @@ SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
current_composition_params_
[
view_id
]
==
params
)
{
return
picture_recorders_
[
view_id
]
->
getRecordingCanvas
();
}
current_composition_params_
[
view_id
]
=
params
;
CGFloat
screenScale
=
[[
UIScreen
mainScreen
]
scale
];
CGRect
rect
=
CGRectMake
(
params
.
offsetPixels
.
x
()
/
screenScale
,
params
.
offsetPixels
.
y
()
/
screenScale
,
params
.
sizePoints
.
width
(),
params
.
sizePoints
.
height
());
UIView
*
touch_interceptor
=
touch_interceptors_
[
view_id
].
get
();
[
touch_interceptor
setFrame
:
rect
];
current_composition_params_
[
view_id
]
=
EmbeddedViewParams
(
params
);
CompositeWithParams
(
view_id
,
params
);
return
picture_recorders_
[
view_id
]
->
getRecordingCanvas
();
}
...
...
@@ -217,6 +322,7 @@ void FlutterPlatformViewsController::Reset() {
active_composition_order_
.
clear
();
picture_recorders_
.
clear
();
current_composition_params_
.
clear
();
clip_count_
.
clear
();
}
bool
FlutterPlatformViewsController
::
SubmitFrame
(
bool
gl_rendering
,
...
...
@@ -249,15 +355,18 @@ bool FlutterPlatformViewsController::SubmitFrame(bool gl_rendering,
for
(
size_t
i
=
0
;
i
<
composition_order_
.
size
();
i
++
)
{
int
view_id
=
composition_order_
[
i
];
UIView
*
intercepter
=
touch_interceptors_
[
view_id
].
get
();
// We added a chain of super views to the platform view to handle clipping.
// The `platform_view_root` is the view at the top of the chain which is a direct subview of the
// `FlutterView`.
UIView
*
platform_view_root
=
root_views_
[
view_id
].
get
();
UIView
*
overlay
=
overlays_
[
view_id
]
->
overlay_view
;
FML_CHECK
(
intercepter
.
superview
==
overlay
.
superview
);
FML_CHECK
(
platform_view_root
.
superview
==
overlay
.
superview
);
if
(
intercepter
.
superview
==
flutter_view
)
{
[
flutter_view
bringSubviewToFront
:
intercepter
];
if
(
platform_view_root
.
superview
==
flutter_view
)
{
[
flutter_view
bringSubviewToFront
:
platform_view_root
];
[
flutter_view
bringSubviewToFront
:
overlay
];
}
else
{
[
flutter_view
addSubview
:
intercepter
];
[
flutter_view
addSubview
:
platform_view_root
];
[
flutter_view
addSubview
:
overlay
];
}
...
...
@@ -276,10 +385,14 @@ void FlutterPlatformViewsController::DetachUnusedLayers() {
for
(
int64_t
view_id
:
active_composition_order_
)
{
if
(
composition_order_set
.
find
(
view_id
)
==
composition_order_set
.
end
())
{
if
(
touch_interceptors_
.
find
(
view_id
)
==
touch_interceptor
s_
.
end
())
{
if
(
root_views_
.
find
(
view_id
)
==
root_view
s_
.
end
())
{
continue
;
}
[
touch_interceptors_
[
view_id
].
get
()
removeFromSuperview
];
// We added a chain of super views to the platform view to handle clipping.
// The `platform_view_root` is the view at the top of the chain which is a direct subview of
// the `FlutterView`.
UIView
*
platform_view_root
=
root_views_
[
view_id
].
get
();
[
platform_view_root
removeFromSuperview
];
[
overlays_
[
view_id
]
->
overlay_view
.
get
()
removeFromSuperview
];
}
}
...
...
@@ -291,12 +404,14 @@ void FlutterPlatformViewsController::DisposeViews() {
}
for
(
int64_t
viewId
:
views_to_dispose_
)
{
UIView
*
touch_interceptor
=
touch_interceptor
s_
[
viewId
].
get
();
[
touch_interceptor
removeFromSuperview
];
UIView
*
root_view
=
root_view
s_
[
viewId
].
get
();
[
root_view
removeFromSuperview
];
views_
.
erase
(
viewId
);
touch_interceptors_
.
erase
(
viewId
);
root_views_
.
erase
(
viewId
);
overlays_
.
erase
(
viewId
);
current_composition_params_
.
erase
(
viewId
);
clip_count_
.
erase
(
viewId
);
}
views_to_dispose_
.
clear
();
}
...
...
shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
浏览文件 @
ebb5b909
...
...
@@ -28,8 +28,29 @@
-
(
void
)
blockGesture
;
@end
// The parent view handles clipping to its subviews.
@interface
ChildClippingView
:
UIView
// Performs the clipping based on the type.
//
// The `type` must be one of the 3: clip_rect, clip_rrect, clip_path.
-
(
void
)
setClip
:(
flutter
::
MutatorType
)
type
rect
:(
const
SkRect
&
)
rect
rrect
:(
const
SkRRect
&
)
rrect
path
:(
const
SkPath
&
)
path
;
@end
namespace
flutter
{
// Converts a SkMatrix to CATransform3D.
// Certain fields are ignored in CATransform3D since SkMatrix is 3x3 and CATransform3D is 4x4.
CATransform3D
GetCATransform3DFromSkMatrix
(
const
SkMatrix
&
matrix
);
// Reset the anchor of `layer` to match the tranform operation from flow.
// The position of the `layer` should be unchanged after resetting the anchor.
void
ResetAnchor
(
CALayer
*
layer
);
class
IOSGLContext
;
class
IOSSurface
;
...
...
@@ -88,8 +109,17 @@ class FlutterPlatformViewsController {
std
::
map
<
std
::
string
,
fml
::
scoped_nsobject
<
NSObject
<
FlutterPlatformViewFactory
>>>
factories_
;
std
::
map
<
int64_t
,
fml
::
scoped_nsobject
<
NSObject
<
FlutterPlatformView
>>>
views_
;
std
::
map
<
int64_t
,
fml
::
scoped_nsobject
<
FlutterTouchInterceptingView
>>
touch_interceptors_
;
// Mapping a platform view ID to the top most parent view (root_view) who is a direct child to the
// `flutter_view_`.
//
// The platform view with the view ID is a child of the root view; If the platform view is not
// clipped, and no clipping view is added, the root view will be the intercepting view.
std
::
map
<
int64_t
,
fml
::
scoped_nsobject
<
UIView
>>
root_views_
;
// Mapping a platform view ID to its latest composition params.
std
::
map
<
int64_t
,
EmbeddedViewParams
>
current_composition_params_
;
// Mapping a platform view ID to the count of the clipping operations that were applied to the
// platform view last time it was composited.
std
::
map
<
int64_t
,
int64_t
>
clip_count_
;
std
::
map
<
int64_t
,
std
::
unique_ptr
<
FlutterPlatformViewLayer
>>
overlays_
;
// The GrContext that is currently used by all of the overlay surfaces.
// We track this to know when the GrContext for the Flutter app has changed
...
...
@@ -122,6 +152,40 @@ class FlutterPlatformViewsController {
void
EnsureGLOverlayInitialized
(
int64_t
overlay_id
,
std
::
shared_ptr
<
IOSGLContext
>
gl_context
,
GrContext
*
gr_context
);
// Traverse the `mutators_stack` and return the number of clip operations.
int
CountClips
(
const
MutatorsStack
&
mutators_stack
);
// Make sure that platform_view has exactly clip_count ChildClippingView ancestors.
//
// Existing ChildClippingViews are re-used. If there are currently more ChildClippingView
// ancestors than needed, the extra views are detached. If there are less ChildClippingView
// ancestors than needed, new ChildClippingViews will be added.
//
// If head_clip_view was attached as a subview to FlutterView, the head of the newly constructed
// ChildClippingViews chain is attached to FlutterView in the same position.
//
// Returns the new head of the clip views chain.
UIView
*
ReconstructClipViewsChain
(
int
number_of_clips
,
UIView
*
platform_view
,
UIView
*
head_clip_view
);
// Applies the mutators in the mutators_stack to the UIView chain that was constructed by
// `ReconstructClipViewsChain`
//
// Clips are applied to the super view with a CALayer mask. Transforms are applied to the current
// view that's at the head of the chain. For example the following mutators stack [T_1, C_2, T_3,
// T_4, C_5, T_6] where T denotes a transform and C denotes a clip, will result in the following
// UIView tree:
//
// C_2 -> C_5 -> PLATFORM_VIEW
// (PLATFORM_VIEW is a subview of C_5 which is a subview of C_2)
//
// T_1 is applied to C_2, T_3 and T_4 are applied to C_5, and T_6 is applied to PLATFORM_VIEW.
//
// After each clip operation, we update the head to the super view of the current head.
void
ApplyMutators
(
const
MutatorsStack
&
mutators_stack
,
UIView
*
embedded_view
);
void
CompositeWithParams
(
int
view_id
,
const
flutter
::
EmbeddedViewParams
&
params
);
FML_DISALLOW_COPY_AND_ASSIGN
(
FlutterPlatformViewsController
);
};
...
...
shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
浏览文件 @
ebb5b909
...
...
@@ -21,4 +21,144 @@ FlutterPlatformViewsController::FlutterPlatformViewsController() = default;
FlutterPlatformViewsController
::~
FlutterPlatformViewsController
()
=
default
;
CATransform3D
GetCATransform3DFromSkMatrix
(
const
SkMatrix
&
matrix
)
{
// Skia only supports 2D transform so we don't map z.
CATransform3D
transform
=
CATransform3DIdentity
;
transform
.
m11
=
matrix
.
getScaleX
();
transform
.
m21
=
matrix
.
getSkewX
();
transform
.
m41
=
matrix
.
getTranslateX
();
transform
.
m14
=
matrix
.
getPerspX
();
transform
.
m12
=
matrix
.
getSkewY
();
transform
.
m22
=
matrix
.
getScaleY
();
transform
.
m42
=
matrix
.
getTranslateY
();
transform
.
m24
=
matrix
.
getPerspY
();
return
transform
;
}
void
ResetAnchor
(
CALayer
*
layer
)
{
// Flow uses (0, 0) to apply transform matrix so we need to match that in Quartz.
layer
.
anchorPoint
=
CGPointZero
;
layer
.
position
=
CGPointZero
;
}
}
// namespace flutter
@implementation
ChildClippingView
+
(
CGRect
)
getCGRectFromSkRect
:(
const
SkRect
&
)
clipSkRect
{
return
CGRectMake
(
clipSkRect
.
fLeft
,
clipSkRect
.
fTop
,
clipSkRect
.
fRight
-
clipSkRect
.
fLeft
,
clipSkRect
.
fBottom
-
clipSkRect
.
fTop
);
}
-
(
void
)
clipRect
:(
const
SkRect
&
)
clipSkRect
{
CGRect
clipRect
=
[
ChildClippingView
getCGRectFromSkRect
:
clipSkRect
];
CGPathRef
pathRef
=
CGPathCreateWithRect
(
clipRect
,
nil
);
CAShapeLayer
*
clip
=
[[
CAShapeLayer
alloc
]
init
];
clip
.
path
=
pathRef
;
self
.
layer
.
mask
=
clip
;
CGPathRelease
(
pathRef
);
}
-
(
void
)
clipRRect
:(
const
SkRRect
&
)
clipSkRRect
{
CGPathRef
pathRef
=
nullptr
;
switch
(
clipSkRRect
.
getType
())
{
case
SkRRect
::
kEmpty_Type
:
{
break
;
}
case
SkRRect
::
kRect_Type
:
{
[
self
clipRect
:
clipSkRRect
.
rect
()];
return
;
}
case
SkRRect
::
kOval_Type
:
case
SkRRect
::
kSimple_Type
:
{
CGRect
clipRect
=
[
ChildClippingView
getCGRectFromSkRect
:
clipSkRRect
.
rect
()];
pathRef
=
CGPathCreateWithRoundedRect
(
clipRect
,
clipSkRRect
.
getSimpleRadii
().
x
(),
clipSkRRect
.
getSimpleRadii
().
y
(),
nil
);
break
;
}
case
SkRRect
::
kNinePatch_Type
:
case
SkRRect
::
kComplex_Type
:
{
CGMutablePathRef
mutablePathRef
=
CGPathCreateMutable
();
// Complex types, we manually add each corner.
SkRect
clipSkRect
=
clipSkRRect
.
rect
();
SkVector
topLeftRadii
=
clipSkRRect
.
radii
(
SkRRect
::
kUpperLeft_Corner
);
SkVector
topRightRadii
=
clipSkRRect
.
radii
(
SkRRect
::
kUpperRight_Corner
);
SkVector
bottomRightRadii
=
clipSkRRect
.
radii
(
SkRRect
::
kLowerRight_Corner
);
SkVector
bottomLeftRadii
=
clipSkRRect
.
radii
(
SkRRect
::
kLowerLeft_Corner
);
// Start drawing RRect
// Move point to the top left corner adding the top left radii's x.
CGPathMoveToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fLeft
+
topLeftRadii
.
x
(),
clipSkRect
.
fTop
);
// Move point horizontally right to the top right corner and add the top right curve.
CGPathAddLineToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fRight
-
topRightRadii
.
x
(),
clipSkRect
.
fTop
);
CGPathAddCurveToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fRight
,
clipSkRect
.
fTop
,
clipSkRect
.
fRight
,
clipSkRect
.
fTop
+
topRightRadii
.
y
(),
clipSkRect
.
fRight
,
clipSkRect
.
fTop
+
topRightRadii
.
y
());
// Move point vertically down to the bottom right corner and add the bottom right curve.
CGPathAddLineToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fRight
,
clipSkRect
.
fBottom
-
bottomRightRadii
.
y
());
CGPathAddCurveToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fRight
,
clipSkRect
.
fBottom
,
clipSkRect
.
fRight
-
bottomRightRadii
.
x
(),
clipSkRect
.
fBottom
,
clipSkRect
.
fRight
-
bottomRightRadii
.
x
(),
clipSkRect
.
fBottom
);
// Move point horizontally left to the bottom left corner and add the bottom left curve.
CGPathAddLineToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fLeft
+
bottomLeftRadii
.
x
(),
clipSkRect
.
fBottom
);
CGPathAddCurveToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fLeft
,
clipSkRect
.
fBottom
,
clipSkRect
.
fLeft
,
clipSkRect
.
fBottom
-
bottomLeftRadii
.
y
(),
clipSkRect
.
fLeft
,
clipSkRect
.
fBottom
-
bottomLeftRadii
.
y
());
// Move point vertically up to the top left corner and add the top left curve.
CGPathAddLineToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fLeft
,
clipSkRect
.
fTop
+
topLeftRadii
.
y
());
CGPathAddCurveToPoint
(
mutablePathRef
,
nil
,
clipSkRect
.
fLeft
,
clipSkRect
.
fTop
,
clipSkRect
.
fLeft
+
topLeftRadii
.
x
(),
clipSkRect
.
fTop
,
clipSkRect
.
fLeft
+
topLeftRadii
.
x
(),
clipSkRect
.
fTop
);
CGPathCloseSubpath
(
mutablePathRef
);
pathRef
=
mutablePathRef
;
break
;
}
}
// TODO(cyanglaz): iOS does not seem to support hard edge on CAShapeLayer. It clearly stated that
// the CAShaperLayer will be drawn antialiased. Need to figure out a way to do the hard edge
// clipping on iOS.
CAShapeLayer
*
clip
=
[[
CAShapeLayer
alloc
]
init
];
clip
.
path
=
pathRef
;
self
.
layer
.
mask
=
clip
;
CGPathRelease
(
pathRef
);
}
-
(
void
)
setClip
:(
flutter
::
MutatorType
)
type
rect
:(
const
SkRect
&
)
rect
rrect
:(
const
SkRRect
&
)
rrect
path
:(
const
SkPath
&
)
path
{
FML_CHECK
(
type
==
flutter
::
clip_rect
||
type
==
flutter
::
clip_rrect
||
type
==
flutter
::
clip_path
);
switch
(
type
)
{
case
flutter
::
clip_rect
:
[
self
clipRect
:
rect
];
break
;
case
flutter
::
clip_rrect
:
[
self
clipRRect
:
rrect
];
break
;
case
flutter
::
clip_path
:
// TODO(cyanglaz): Add clip path
break
;
default:
break
;
}
}
// The ChildClippingView is as big as the FlutterView, we only want touches to be hit tested and
// consumed by this view if they are inside the smaller child view.
-
(
BOOL
)
pointInside
:(
CGPoint
)
point
withEvent
:(
UIEvent
*
)
event
{
for
(
UIView
*
view
in
self
.
subviews
)
{
if
([
view
pointInside
:[
self
convertPoint
:
point
toView
:
view
]
withEvent
:
event
])
{
return
YES
;
}
}
return
NO
;
}
@end
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录