Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
f2a8b050
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,发现更多精彩内容 >>
未验证
提交
f2a8b050
编写于
10月 08, 2019
作者:
F
Ferhat
提交者:
GitHub
10月 08, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[web] Add support for path transform (#12794)
* Implement path.transform
上级
5d61a019
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
654 addition
and
199 deletion
+654
-199
ci/licenses_golden/licenses_flutter
ci/licenses_golden/licenses_flutter
+1
-0
lib/web_ui/lib/src/engine.dart
lib/web_ui/lib/src/engine.dart
+1
-0
lib/web_ui/lib/src/engine/bitmap_canvas.dart
lib/web_ui/lib/src/engine/bitmap_canvas.dart
+6
-191
lib/web_ui/lib/src/engine/recording_canvas.dart
lib/web_ui/lib/src/engine/recording_canvas.dart
+179
-0
lib/web_ui/lib/src/engine/rrect_renderer.dart
lib/web_ui/lib/src/engine/rrect_renderer.dart
+224
-0
lib/web_ui/lib/src/ui/canvas.dart
lib/web_ui/lib/src/ui/canvas.dart
+17
-8
lib/web_ui/test/golden_tests/engine/path_transform_test.dart
lib/web_ui/test/golden_tests/engine/path_transform_test.dart
+226
-0
未找到文件。
ci/licenses_golden/licenses_flutter
浏览文件 @
f2a8b050
...
...
@@ -390,6 +390,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/platform_views.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/plugins.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_binding.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/recording_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/rrect_renderer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart
...
...
lib/web_ui/lib/src/engine.dart
浏览文件 @
f2a8b050
...
...
@@ -57,6 +57,7 @@ part 'engine/platform_views.dart';
part
'engine/plugins.dart'
;
part
'engine/pointer_binding.dart'
;
part
'engine/recording_canvas.dart'
;
part
'engine/rrect_renderer.dart'
;
part
'engine/semantics/accessibility.dart'
;
part
'engine/semantics/checkable.dart'
;
part
'engine/semantics/image.dart'
;
...
...
lib/web_ui/lib/src/engine/bitmap_canvas.dart
浏览文件 @
f2a8b050
...
...
@@ -454,202 +454,16 @@ class BitmapCanvas extends EngineCanvas with SaveStackTracking {
@override
void
drawRRect
(
ui
.
RRect
rrect
,
ui
.
PaintData
paint
)
{
_applyPaint
(
paint
);
_
drawRRectPath
(
rrect
);
_
RRectToCanvasRenderer
(
ctx
).
render
(
rrect
);
_strokeOrFill
(
paint
);
}
void
_drawRRectPath
(
ui
.
RRect
inputRRect
,
{
bool
startNewPath
=
true
})
{
// TODO(mdebbar): Backport the overlapping corners fix to houdini_painter.js
// To draw the rounded rectangle, perform the following steps:
// 0. Ensure border radius don't overlap
// 1. Flip left,right top,bottom since web doesn't support flipped
// coordinates with negative radii.
// 2. draw the line for the top
// 3. draw the arc for the top-right corner
// 4. draw the line for the right side
// 5. draw the arc for the bottom-right corner
// 6. draw the line for the bottom of the rectangle
// 7. draw the arc for the bottom-left corner
// 8. draw the line for the left side
// 9. draw the arc for the top-left corner
//
// After drawing, the current point will be the left side of the top of the
// rounded rectangle (after the corner).
// TODO(het): Confirm that this is the end point in Flutter for RRect
// Ensure border radius curves never overlap
final
ui
.
RRect
rrect
=
inputRRect
.
scaleRadii
();
double
left
=
rrect
.
left
;
double
right
=
rrect
.
right
;
double
top
=
rrect
.
top
;
double
bottom
=
rrect
.
bottom
;
if
(
left
>
right
)
{
left
=
right
;
right
=
rrect
.
left
;
}
if
(
top
>
bottom
)
{
top
=
bottom
;
bottom
=
rrect
.
top
;
}
final
double
trRadiusX
=
rrect
.
trRadiusX
.
abs
();
final
double
tlRadiusX
=
rrect
.
tlRadiusX
.
abs
();
final
double
trRadiusY
=
rrect
.
trRadiusY
.
abs
();
final
double
tlRadiusY
=
rrect
.
tlRadiusY
.
abs
();
final
double
blRadiusX
=
rrect
.
blRadiusX
.
abs
();
final
double
brRadiusX
=
rrect
.
brRadiusX
.
abs
();
final
double
blRadiusY
=
rrect
.
blRadiusY
.
abs
();
final
double
brRadiusY
=
rrect
.
brRadiusY
.
abs
();
if
(
startNewPath
)
{
ctx
.
beginPath
();
}
ctx
.
moveTo
(
left
+
trRadiusX
,
top
);
// Top side and top-right corner
ctx
.
lineTo
(
right
-
trRadiusX
,
top
);
ctx
.
ellipse
(
right
-
trRadiusX
,
top
+
trRadiusY
,
trRadiusX
,
trRadiusY
,
0
,
1.5
*
math
.
pi
,
2.0
*
math
.
pi
,
false
,
);
// Right side and bottom-right corner
ctx
.
lineTo
(
right
,
bottom
-
brRadiusY
);
ctx
.
ellipse
(
right
-
brRadiusX
,
bottom
-
brRadiusY
,
brRadiusX
,
brRadiusY
,
0
,
0
,
0.5
*
math
.
pi
,
false
,
);
// Bottom side and bottom-left corner
ctx
.
lineTo
(
left
+
blRadiusX
,
bottom
);
ctx
.
ellipse
(
left
+
blRadiusX
,
bottom
-
blRadiusY
,
blRadiusX
,
blRadiusY
,
0
,
0.5
*
math
.
pi
,
math
.
pi
,
false
,
);
// Left side and top-left corner
ctx
.
lineTo
(
left
,
top
+
tlRadiusY
);
ctx
.
ellipse
(
left
+
tlRadiusX
,
top
+
tlRadiusY
,
tlRadiusX
,
tlRadiusY
,
0
,
math
.
pi
,
1.5
*
math
.
pi
,
false
,
);
}
void
_drawRRectPathReverse
(
ui
.
RRect
inputRRect
,
{
bool
startNewPath
=
true
})
{
// Ensure border radius curves never overlap
final
ui
.
RRect
rrect
=
inputRRect
.
scaleRadii
();
double
left
=
rrect
.
left
;
double
right
=
rrect
.
right
;
double
top
=
rrect
.
top
;
double
bottom
=
rrect
.
bottom
;
final
double
trRadiusX
=
rrect
.
trRadiusX
.
abs
();
final
double
tlRadiusX
=
rrect
.
tlRadiusX
.
abs
();
final
double
trRadiusY
=
rrect
.
trRadiusY
.
abs
();
final
double
tlRadiusY
=
rrect
.
tlRadiusY
.
abs
();
final
double
blRadiusX
=
rrect
.
blRadiusX
.
abs
();
final
double
brRadiusX
=
rrect
.
brRadiusX
.
abs
();
final
double
blRadiusY
=
rrect
.
blRadiusY
.
abs
();
final
double
brRadiusY
=
rrect
.
brRadiusY
.
abs
();
if
(
left
>
right
)
{
left
=
right
;
right
=
rrect
.
left
;
}
if
(
top
>
bottom
)
{
top
=
bottom
;
bottom
=
rrect
.
top
;
}
// Draw the rounded rectangle, counterclockwise.
ctx
.
moveTo
(
right
-
trRadiusX
,
top
);
if
(
startNewPath
)
{
ctx
.
beginPath
();
}
// Top side and top-left corner
ctx
.
lineTo
(
left
+
tlRadiusX
,
top
);
ctx
.
ellipse
(
left
+
tlRadiusX
,
top
+
tlRadiusY
,
tlRadiusX
,
tlRadiusY
,
0
,
1.5
*
math
.
pi
,
1
*
math
.
pi
,
true
,
);
// Left side and bottom-left corner
ctx
.
lineTo
(
left
,
bottom
-
blRadiusY
);
ctx
.
ellipse
(
left
+
blRadiusX
,
bottom
-
blRadiusY
,
blRadiusX
,
blRadiusY
,
0
,
1
*
math
.
pi
,
0.5
*
math
.
pi
,
true
,
);
// Bottom side and bottom-right corner
ctx
.
lineTo
(
right
-
brRadiusX
,
bottom
);
ctx
.
ellipse
(
right
-
brRadiusX
,
bottom
-
brRadiusY
,
brRadiusX
,
brRadiusY
,
0
,
0.5
*
math
.
pi
,
0
*
math
.
pi
,
true
,
);
// Right side and top-right corner
ctx
.
lineTo
(
right
,
top
+
trRadiusY
);
ctx
.
ellipse
(
right
-
trRadiusX
,
top
+
trRadiusY
,
trRadiusX
,
trRadiusY
,
0
,
0
*
math
.
pi
,
1.5
*
math
.
pi
,
true
,
);
}
@override
void
drawDRRect
(
ui
.
RRect
outer
,
ui
.
RRect
inner
,
ui
.
PaintData
paint
)
{
_applyPaint
(
paint
);
_drawRRectPath
(
outer
);
_drawRRectPathReverse
(
inner
,
startNewPath:
false
);
_RRectRenderer
renderer
=
_RRectToCanvasRenderer
(
ctx
);
renderer
.
render
(
outer
);
renderer
.
render
(
inner
,
startNewPath:
false
,
reverse:
true
);
_strokeOrFill
(
paint
);
}
...
...
@@ -886,7 +700,8 @@ class BitmapCanvas extends EngineCanvas with SaveStackTracking {
break
;
case
PathCommandTypes
.
rRect
:
final
RRectCommand
rrectCommand
=
command
;
_drawRRectPath
(
rrectCommand
.
rrect
,
startNewPath:
false
);
_RRectToCanvasRenderer
(
ctx
).
render
(
rrectCommand
.
rrect
,
startNewPath:
false
);
break
;
case
PathCommandTypes
.
rect
:
final
RectCommand
rectCommand
=
command
;
...
...
lib/web_ui/lib/src/engine/recording_canvas.dart
浏览文件 @
f2a8b050
...
...
@@ -1128,6 +1128,14 @@ abstract class PathCommand {
PathCommand
shifted
(
ui
.
Offset
offset
);
List
<
dynamic
>
serializeToCssPaint
();
/// Transform the command and add to targetPath.
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
);
/// Helper method for implementing transforms.
static
ui
.
Offset
_transformOffset
(
double
x
,
double
y
,
Float64List
matrix4
)
=>
ui
.
Offset
((
matrix4
[
0
]
*
x
)
+
(
matrix4
[
4
]
*
y
)
+
matrix4
[
12
],
(
matrix4
[
1
]
*
x
)
+
(
matrix4
[
5
]
*
y
)
+
matrix4
[
13
]);
}
class
MoveTo
extends
PathCommand
{
...
...
@@ -1146,6 +1154,12 @@ class MoveTo extends PathCommand {
return
<
dynamic
>[
1
,
x
,
y
];
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
ui
.
Offset
offset
=
PathCommand
.
_transformOffset
(
x
,
y
,
matrix4
);
targetPath
.
moveTo
(
offset
.
dx
,
offset
.
dy
);
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
...
...
@@ -1172,6 +1186,12 @@ class LineTo extends PathCommand {
return
<
dynamic
>[
2
,
x
,
y
];
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
ui
.
Offset
offset
=
PathCommand
.
_transformOffset
(
x
,
y
,
matrix4
);
targetPath
.
lineTo
(
offset
.
dx
,
offset
.
dy
);
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
...
...
@@ -1217,6 +1237,87 @@ class Ellipse extends PathCommand {
];
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
ui
.
Path
bezierPath
=
ui
.
Path
();
_drawArcWithBezier
(
x
,
y
,
radiusX
,
radiusY
,
rotation
,
startAngle
,
anticlockwise
?
startAngle
-
endAngle
:
endAngle
-
startAngle
,
matrix4
,
bezierPath
);
targetPath
.
addPath
(
bezierPath
,
ui
.
Offset
.
zero
,
matrix4:
matrix4
);
}
void
_drawArcWithBezier
(
double
centerX
,
double
centerY
,
double
radiusX
,
double
radiusY
,
double
rotation
,
double
startAngle
,
double
sweep
,
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
double
ratio
=
sweep
.
abs
()
/
(
math
.
pi
/
2.0
);
if
((
1.0
-
ratio
).
abs
()
<
0.0000001
)
{
ratio
=
1.0
;
}
final
int
segments
=
math
.
max
(
ratio
.
ceil
(),
1
);
final
double
anglePerSegment
=
sweep
/
segments
;
double
angle
=
startAngle
;
for
(
int
segment
=
0
;
segment
<
segments
;
segment
++)
{
_drawArcSegment
(
targetPath
,
centerX
,
centerY
,
radiusX
,
radiusY
,
rotation
,
angle
,
anglePerSegment
,
segment
==
0
,
matrix4
);
angle
+=
anglePerSegment
;
}
}
void
_drawArcSegment
(
ui
.
Path
path
,
double
centerX
,
double
centerY
,
double
radiusX
,
double
radiusY
,
double
rotation
,
double
startAngle
,
double
sweep
,
bool
startPath
,
Float64List
matrix4
)
{
final
double
s
=
4
/
3
*
math
.
tan
(
sweep
/
4
);
// Rotate unit vector to startAngle and endAngle to use for computing start
// and end points of segment.
final
double
x1
=
math
.
cos
(
startAngle
);
final
double
y1
=
math
.
sin
(
startAngle
);
final
double
endAngle
=
startAngle
+
sweep
;
final
double
x2
=
math
.
cos
(
endAngle
);
final
double
y2
=
math
.
sin
(
endAngle
);
// Compute scaled curve control points.
final
double
cpx1
=
(
x1
-
y1
*
s
)
*
radiusX
;
final
double
cpy1
=
(
y1
+
x1
*
s
)
*
radiusY
;
final
double
cpx2
=
(
x2
+
y2
*
s
)
*
radiusX
;
final
double
cpy2
=
(
y2
-
x2
*
s
)
*
radiusY
;
final
double
endPointX
=
centerX
+
x2
*
radiusX
;
final
double
endPointY
=
centerY
+
y2
*
radiusY
;
final
double
rotationRad
=
rotation
*
math
.
pi
/
180.0
;
final
double
cosR
=
math
.
cos
(
rotationRad
);
final
double
sinR
=
math
.
sin
(
rotationRad
);
if
(
startPath
)
{
final
double
scaledX1
=
x1
*
radiusX
;
final
double
scaledY1
=
y1
*
radiusY
;
if
(
rotation
==
0.0
)
{
path
.
moveTo
(
centerX
+
scaledX1
,
centerY
+
scaledY1
);
}
else
{
final
double
rotatedStartX
=
(
scaledX1
*
cosR
)
+
(
scaledY1
*
sinR
);
final
double
rotatedStartY
=
(
scaledY1
*
cosR
)
-
(
scaledX1
*
sinR
);
path
.
moveTo
(
centerX
+
rotatedStartX
,
centerY
+
rotatedStartY
);
}
}
if
(
rotation
==
0.0
)
{
path
.
cubicTo
(
centerX
+
cpx1
,
centerY
+
cpy1
,
centerX
+
cpx2
,
centerY
+
cpy2
,
endPointX
,
endPointY
);
}
else
{
final
double
rotatedCpx1
=
centerX
+
(
cpx1
*
cosR
)
+
(
cpy1
*
sinR
);
final
double
rotatedCpy1
=
centerY
+
(
cpy1
*
cosR
)
-
(
cpx1
*
sinR
);
final
double
rotatedCpx2
=
centerX
+
(
cpx2
*
cosR
)
+
(
cpy2
*
sinR
);
final
double
rotatedCpy2
=
centerY
+
(
cpy2
*
cosR
)
-
(
cpx2
*
sinR
);
final
double
rotatedEndX
=
centerX
+
((
endPointX
-
centerX
)
*
cosR
)
+
((
endPointY
-
centerY
)
*
sinR
);
final
double
rotatedEndY
=
centerY
+
((
endPointY
-
centerY
)
*
cosR
)
-
((
endPointX
-
centerX
)
*
sinR
);
path
.
cubicTo
(
rotatedCpx1
,
rotatedCpy1
,
rotatedCpx2
,
rotatedCpy2
,
rotatedEndX
,
rotatedEndY
);
}
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
...
...
@@ -1247,6 +1348,22 @@ class QuadraticCurveTo extends PathCommand {
return
<
dynamic
>[
4
,
x1
,
y1
,
x2
,
y2
];
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
double
m0
=
matrix4
[
0
];
final
double
m1
=
matrix4
[
1
];
final
double
m4
=
matrix4
[
4
];
final
double
m5
=
matrix4
[
5
];
final
double
m12
=
matrix4
[
12
];
final
double
m13
=
matrix4
[
13
];
final
double
transformedX1
=
(
m0
*
x1
)
+
(
m4
*
y1
)
+
m12
;
final
double
transformedY1
=
(
m1
*
x1
)
+
(
m5
*
y1
)
+
m13
;
final
double
transformedX2
=
(
m0
*
x2
)
+
(
m4
*
y2
)
+
m12
;
final
double
transformedY2
=
(
m1
*
x2
)
+
(
m5
*
y2
)
+
m13
;
targetPath
.
quadraticBezierTo
(
transformedX1
,
transformedY1
,
transformedX2
,
transformedY2
);
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
...
...
@@ -1279,6 +1396,24 @@ class BezierCurveTo extends PathCommand {
return
<
dynamic
>[
5
,
x1
,
y1
,
x2
,
y2
,
x3
,
y3
];
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
double
s0
=
matrix4
[
0
];
final
double
s1
=
matrix4
[
1
];
final
double
s4
=
matrix4
[
4
];
final
double
s5
=
matrix4
[
5
];
final
double
s12
=
matrix4
[
12
];
final
double
s13
=
matrix4
[
13
];
final
double
transformedX1
=
(
s0
*
x1
)
+
(
s4
*
y1
)
+
s12
;
final
double
transformedY1
=
(
s1
*
x1
)
+
(
s5
*
y1
)
+
s13
;
final
double
transformedX2
=
(
s0
*
x2
)
+
(
s4
*
y2
)
+
s12
;
final
double
transformedY2
=
(
s1
*
x2
)
+
(
s5
*
y2
)
+
s13
;
final
double
transformedX3
=
(
s0
*
x3
)
+
(
s4
*
y3
)
+
s12
;
final
double
transformedY3
=
(
s1
*
x3
)
+
(
s5
*
y3
)
+
s13
;
targetPath
.
cubicTo
(
transformedX1
,
transformedY1
,
transformedX2
,
transformedY2
,
transformedX3
,
transformedY3
);
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
...
...
@@ -1303,6 +1438,38 @@ class RectCommand extends PathCommand {
return
RectCommand
(
x
+
offset
.
dx
,
y
+
offset
.
dy
,
width
,
height
);
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
double
s0
=
matrix4
[
0
];
final
double
s1
=
matrix4
[
1
];
final
double
s4
=
matrix4
[
4
];
final
double
s5
=
matrix4
[
5
];
final
double
s12
=
matrix4
[
12
];
final
double
s13
=
matrix4
[
13
];
final
double
transformedX1
=
(
s0
*
x
)
+
(
s4
*
y
)
+
s12
;
final
double
transformedY1
=
(
s1
*
x
)
+
(
s5
*
y
)
+
s13
;
final
double
x2
=
x
+
width
;
final
double
y2
=
y
+
height
;
final
double
transformedX2
=
(
s0
*
x2
)
+
(
s4
*
y
)
+
s12
;
final
double
transformedY2
=
(
s1
*
x2
)
+
(
s5
*
y
)
+
s13
;
final
double
transformedX3
=
(
s0
*
x2
)
+
(
s4
*
y2
)
+
s12
;
final
double
transformedY3
=
(
s1
*
x2
)
+
(
s5
*
y2
)
+
s13
;
final
double
transformedX4
=
(
s0
*
x
)
+
(
s4
*
y2
)
+
s12
;
final
double
transformedY4
=
(
s1
*
x
)
+
(
s5
*
y2
)
+
s13
;
if
(
transformedY1
==
transformedY2
&&
transformedY3
==
transformedY4
&&
transformedX1
==
transformedX4
&&
transformedX2
==
transformedX3
)
{
// It is still a rectangle.
targetPath
.
addRect
(
ui
.
Rect
.
fromLTRB
(
transformedX1
,
transformedY1
,
transformedX3
,
transformedY3
));
}
else
{
targetPath
.
moveTo
(
transformedX1
,
transformedY1
);
targetPath
.
lineTo
(
transformedX2
,
transformedY2
);
targetPath
.
lineTo
(
transformedX3
,
transformedY3
);
targetPath
.
lineTo
(
transformedX4
,
transformedY4
);
targetPath
.
close
();
}
}
@override
List
<
dynamic
>
serializeToCssPaint
()
{
return
<
dynamic
>[
6
,
x
,
y
,
width
,
height
];
...
...
@@ -1334,6 +1501,13 @@ class RRectCommand extends PathCommand {
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
final
ui
.
Path
roundRectPath
=
ui
.
Path
();
_RRectToPathRenderer
(
roundRectPath
).
render
(
rrect
);
targetPath
.
addPath
(
roundRectPath
,
ui
.
Offset
.
zero
,
matrix4:
matrix4
);
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
return
'
$rrect
'
;
...
...
@@ -1356,6 +1530,11 @@ class CloseCommand extends PathCommand {
return
<
dynamic
>[
8
];
}
@override
void
transform
(
Float64List
matrix4
,
ui
.
Path
targetPath
)
{
targetPath
.
close
();
}
@override
String
toString
()
{
if
(
assertionsEnabled
)
{
...
...
lib/web_ui/lib/src/engine/rrect_renderer.dart
0 → 100644
浏览文件 @
f2a8b050
// 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.
part of
engine
;
/// Renders an RRect using path primitives.
abstract
class
_RRectRenderer
{
// TODO(mdebbar): Backport the overlapping corners fix to houdini_painter.js
// To draw the rounded rectangle, perform the following steps:
// 0. Ensure border radius don't overlap
// 1. Flip left,right top,bottom since web doesn't support flipped
// coordinates with negative radii.
// 2. draw the line for the top
// 3. draw the arc for the top-right corner
// 4. draw the line for the right side
// 5. draw the arc for the bottom-right corner
// 6. draw the line for the bottom of the rectangle
// 7. draw the arc for the bottom-left corner
// 8. draw the line for the left side
// 9. draw the arc for the top-left corner
//
// After drawing, the current point will be the left side of the top of the
// rounded rectangle (after the corner).
// TODO(het): Confirm that this is the end point in Flutter for RRect
void
render
(
ui
.
RRect
inputRRect
,
{
bool
startNewPath
=
true
,
bool
reverse
=
false
})
{
// Ensure border radius curves never overlap
final
ui
.
RRect
rrect
=
inputRRect
.
scaleRadii
();
double
left
=
rrect
.
left
;
double
right
=
rrect
.
right
;
double
top
=
rrect
.
top
;
double
bottom
=
rrect
.
bottom
;
if
(
left
>
right
)
{
left
=
right
;
right
=
rrect
.
left
;
}
if
(
top
>
bottom
)
{
top
=
bottom
;
bottom
=
rrect
.
top
;
}
final
double
trRadiusX
=
rrect
.
trRadiusX
.
abs
();
final
double
tlRadiusX
=
rrect
.
tlRadiusX
.
abs
();
final
double
trRadiusY
=
rrect
.
trRadiusY
.
abs
();
final
double
tlRadiusY
=
rrect
.
tlRadiusY
.
abs
();
final
double
blRadiusX
=
rrect
.
blRadiusX
.
abs
();
final
double
brRadiusX
=
rrect
.
brRadiusX
.
abs
();
final
double
blRadiusY
=
rrect
.
blRadiusY
.
abs
();
final
double
brRadiusY
=
rrect
.
brRadiusY
.
abs
();
if
(!
reverse
)
{
if
(
startNewPath
)
{
beginPath
();
}
moveTo
(
left
+
trRadiusX
,
top
);
// Top side and top-right corner
lineTo
(
right
-
trRadiusX
,
top
);
ellipse
(
right
-
trRadiusX
,
top
+
trRadiusY
,
trRadiusX
,
trRadiusY
,
0
,
1.5
*
math
.
pi
,
2.0
*
math
.
pi
,
false
,
);
// Right side and bottom-right corner
lineTo
(
right
,
bottom
-
brRadiusY
);
ellipse
(
right
-
brRadiusX
,
bottom
-
brRadiusY
,
brRadiusX
,
brRadiusY
,
0
,
0
,
0.5
*
math
.
pi
,
false
,
);
// Bottom side and bottom-left corner
lineTo
(
left
+
blRadiusX
,
bottom
);
ellipse
(
left
+
blRadiusX
,
bottom
-
blRadiusY
,
blRadiusX
,
blRadiusY
,
0
,
0.5
*
math
.
pi
,
math
.
pi
,
false
,
);
// Left side and top-left corner
lineTo
(
left
,
top
+
tlRadiusY
);
ellipse
(
left
+
tlRadiusX
,
top
+
tlRadiusY
,
tlRadiusX
,
tlRadiusY
,
0
,
math
.
pi
,
1.5
*
math
.
pi
,
false
,
);
}
else
{
// Draw the rounded rectangle, counterclockwise.
moveTo
(
right
-
trRadiusX
,
top
);
if
(
startNewPath
)
{
beginPath
();
}
// Top side and top-left corner
lineTo
(
left
+
tlRadiusX
,
top
);
ellipse
(
left
+
tlRadiusX
,
top
+
tlRadiusY
,
tlRadiusX
,
tlRadiusY
,
0
,
1.5
*
math
.
pi
,
1
*
math
.
pi
,
true
,
);
// Left side and bottom-left corner
lineTo
(
left
,
bottom
-
blRadiusY
);
ellipse
(
left
+
blRadiusX
,
bottom
-
blRadiusY
,
blRadiusX
,
blRadiusY
,
0
,
1
*
math
.
pi
,
0.5
*
math
.
pi
,
true
,
);
// Bottom side and bottom-right corner
lineTo
(
right
-
brRadiusX
,
bottom
);
ellipse
(
right
-
brRadiusX
,
bottom
-
brRadiusY
,
brRadiusX
,
brRadiusY
,
0
,
0.5
*
math
.
pi
,
0
*
math
.
pi
,
true
,
);
// Right side and top-right corner
lineTo
(
right
,
top
+
trRadiusY
);
ellipse
(
right
-
trRadiusX
,
top
+
trRadiusY
,
trRadiusX
,
trRadiusY
,
0
,
0
*
math
.
pi
,
1.5
*
math
.
pi
,
true
,
);
}
}
void
beginPath
();
void
moveTo
(
double
x
,
double
y
);
void
lineTo
(
double
x
,
double
y
);
void
ellipse
(
double
centerX
,
double
centerY
,
double
radiusX
,
double
radiusY
,
double
rotation
,
double
startAngle
,
double
endAngle
,
bool
antiClockwise
);
}
/// Renders RRect to a 2d canvas.
class
_RRectToCanvasRenderer
extends
_RRectRenderer
{
final
html
.
CanvasRenderingContext2D
context
;
_RRectToCanvasRenderer
(
this
.
context
);
void
beginPath
()
{
context
.
beginPath
();
}
void
moveTo
(
double
x
,
double
y
)
{
context
.
moveTo
(
x
,
y
);
}
void
lineTo
(
double
x
,
double
y
)
{
context
.
lineTo
(
x
,
y
);
}
void
ellipse
(
double
centerX
,
double
centerY
,
double
radiusX
,
double
radiusY
,
double
rotation
,
double
startAngle
,
double
endAngle
,
bool
antiClockwise
)
{
context
.
ellipse
(
centerX
,
centerY
,
radiusX
,
radiusY
,
rotation
,
startAngle
,
endAngle
,
antiClockwise
);
}
}
/// Renders RRect to a path.
class
_RRectToPathRenderer
extends
_RRectRenderer
{
final
ui
.
Path
path
;
_RRectToPathRenderer
(
this
.
path
);
void
beginPath
()
{}
void
moveTo
(
double
x
,
double
y
)
{
path
.
moveTo
(
x
,
y
);
}
void
lineTo
(
double
x
,
double
y
)
{
path
.
lineTo
(
x
,
y
);
}
void
ellipse
(
double
centerX
,
double
centerY
,
double
radiusX
,
double
radiusY
,
double
rotation
,
double
startAngle
,
double
endAngle
,
bool
antiClockwise
)
{
path
.
addArc
(
ui
.
Rect
.
fromLTRB
(
centerX
-
radiusX
,
centerY
-
radiusY
,
centerX
+
radiusX
,
centerY
+
radiusY
),
startAngle
,
antiClockwise
?
startAngle
-
endAngle
:
endAngle
-
startAngle
);
}
}
lib/web_ui/lib/src/ui/canvas.dart
浏览文件 @
f2a8b050
...
...
@@ -1584,12 +1584,15 @@ class Path {
if
(
dx
==
0.0
&&
dy
==
0.0
)
{
subpaths
.
addAll
(
path
.
subpaths
);
}
else
{
throw
UnimplementedError
(
'Cannot add path with non-zero offset'
);
subpaths
.
addAll
(
path
.
transform
(
engine
.
Matrix4
.
translationValues
(
dx
,
dy
,
0.0
).
storage
).
subpaths
);
}
}
void
_addPathWithMatrix
(
Path
path
,
double
dx
,
double
dy
,
Float64List
matrix
)
{
throw
UnimplementedError
(
'Cannot add path with transform matrix'
);
final
engine
.
Matrix4
transform
=
engine
.
Matrix4
.
fromFloat64List
(
matrix
);
transform
.
translate
(
dx
,
dy
);
subpaths
.
addAll
(
path
.
transform
(
transform
.
storage
).
subpaths
);
}
/// Adds the given path to this path by extending the current segment of this
...
...
@@ -1742,18 +1745,24 @@ class Path {
/// subpath translated by the given offset.
Path
shift
(
Offset
offset
)
{
assert
(
engine
.
offsetIsValid
(
offset
));
final
List
<
engine
.
Subpath
>
shiftedSub
p
aths
=
<
engine
.
Subpath
>[];
for
(
final
engine
.
Subpath
sub
p
ath
in
subpaths
)
{
shiftedSub
paths
.
add
(
subp
ath
.
shift
(
offset
));
final
List
<
engine
.
Subpath
>
shiftedSub
P
aths
=
<
engine
.
Subpath
>[];
for
(
final
engine
.
Subpath
sub
P
ath
in
subpaths
)
{
shiftedSub
Paths
.
add
(
subP
ath
.
shift
(
offset
));
}
return
Path
.
_clone
(
shiftedSub
p
aths
,
fillType
);
return
Path
.
_clone
(
shiftedSub
P
aths
,
fillType
);
}
/// Returns a copy of the path with all the segments of every
/// subpath transformed by the given matrix.
/// sub
path transformed by the given matrix.
Path
transform
(
Float64List
matrix4
)
{
assert
(
engine
.
matrix4IsValid
(
matrix4
));
throw
UnimplementedError
();
final
Path
transformedPath
=
Path
();
for
(
final
engine
.
Subpath
subPath
in
subpaths
)
{
for
(
final
engine
.
PathCommand
cmd
in
subPath
.
commands
)
{
cmd
.
transform
(
matrix4
,
transformedPath
);
}
}
return
transformedPath
;
}
/// Computes the bounding rectangle for this path.
...
...
lib/web_ui/test/golden_tests/engine/path_transform_test.dart
0 → 100644
浏览文件 @
f2a8b050
// 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.
import
'dart:html'
as
html
;
import
'dart:math'
as
math
;
import
'dart:typed_data'
;
import
'package:ui/ui.dart'
hide
TextStyle
;
import
'package:ui/src/engine.dart'
;
import
'package:test/test.dart'
;
import
'../../matchers.dart'
;
import
'package:web_engine_tester/golden_tester.dart'
;
void
main
(
)
async
{
const
double
screenWidth
=
600.0
;
const
double
screenHeight
=
800.0
;
const
Rect
screenRect
=
Rect
.
fromLTWH
(
0
,
0
,
screenWidth
,
screenHeight
);
final
Paint
testPaint
=
Paint
()..
color
=
const
Color
(
0xFFFF0000
);
// Commit a recording canvas to a bitmap, and compare with the expected
Future
<
void
>
_checkScreenshot
(
RecordingCanvas
rc
,
String
fileName
,
{
Rect
region
=
const
Rect
.
fromLTWH
(
0
,
0
,
500
,
500
),
bool
write
=
false
})
async
{
final
EngineCanvas
engineCanvas
=
BitmapCanvas
(
screenRect
);
rc
.
apply
(
engineCanvas
);
// Wrap in <flt-scene> so that our CSS selectors kick in.
final
html
.
Element
sceneElement
=
html
.
Element
.
tag
(
'flt-scene'
);
try
{
sceneElement
.
append
(
engineCanvas
.
rootElement
);
html
.
document
.
body
.
append
(
sceneElement
);
await
matchGoldenFile
(
'
$fileName
.png'
,
region:
region
);
}
finally
{
// The page is reused across tests, so remove the element after taking the
// Scuba screenshot.
sceneElement
.
remove
();
}
}
setUp
(()
async
{
debugEmulateFlutterTesterEnvironment
=
true
;
await
webOnlyInitializePlatform
();
webOnlyFontCollection
.
debugRegisterTestFonts
();
await
webOnlyFontCollection
.
ensureFontsLoaded
();
});
test
(
'Should draw transformed line.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
final
Path
path
=
Path
();
path
.
moveTo
(
0
,
0
);
path
.
lineTo
(
300
,
200
);
rc
.
drawPath
(
path
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
(
0xFF404000
));
final
Path
transformedPath
=
Path
();
final
Matrix4
testMatrixTranslateRotate
=
Matrix4
.
rotationZ
(
math
.
pi
*
30.0
/
180.0
)..
translate
(
100
,
20
);
transformedPath
.
addPath
(
path
,
Offset
.
zero
,
matrix4:
testMatrixTranslateRotate
.
storage
);
rc
.
drawPath
(
transformedPath
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
.
fromRGBO
(
0
,
128
,
255
,
1.0
));
await
_checkScreenshot
(
rc
,
'path_transform_with_line'
);
});
test
(
'Should draw transformed line.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
final
Path
path
=
Path
();
path
.
addRect
(
Rect
.
fromLTRB
(
50
,
40
,
300
,
100
));
rc
.
drawPath
(
path
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
(
0xFF404000
));
final
Path
transformedPath
=
Path
();
final
Matrix4
testMatrixTranslateRotate
=
Matrix4
.
rotationZ
(
math
.
pi
*
30.0
/
180.0
)..
translate
(
100
,
20
);
transformedPath
.
addPath
(
path
,
Offset
.
zero
,
matrix4:
testMatrixTranslateRotate
.
storage
);
rc
.
drawPath
(
transformedPath
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
.
fromRGBO
(
0
,
128
,
255
,
1.0
));
await
_checkScreenshot
(
rc
,
'path_transform_with_rect'
);
});
test
(
'Should draw transformed quadratic curve.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
final
Path
path
=
Path
();
path
.
moveTo
(
100
,
100
);
path
.
quadraticBezierTo
(
100
,
300
,
400
,
300
);
rc
.
drawPath
(
path
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
(
0xFF404000
));
final
Path
transformedPath
=
Path
();
final
Matrix4
testMatrixTranslateRotate
=
Matrix4
.
rotationZ
(
math
.
pi
*
30.0
/
180.0
)..
translate
(
100
,
-
80
);
transformedPath
.
addPath
(
path
,
Offset
.
zero
,
matrix4:
testMatrixTranslateRotate
.
storage
);
rc
.
drawPath
(
transformedPath
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
.
fromRGBO
(
0
,
128
,
255
,
1.0
));
await
_checkScreenshot
(
rc
,
'path_transform_with_quadratic_curve'
);
});
test
(
'Should draw transformed conic.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
const
double
yStart
=
20
;
const
Offset
p0
=
Offset
(
25
,
yStart
+
25
);
const
Offset
pc
=
Offset
(
60
,
yStart
+
150
);
const
Offset
p2
=
Offset
(
100
,
yStart
+
50
);
final
Path
path
=
Path
();
path
.
moveTo
(
p0
.
dx
,
p0
.
dy
);
path
.
conicTo
(
pc
.
dx
,
pc
.
dy
,
p2
.
dx
,
p2
.
dy
,
0.5
);
path
.
close
();
path
.
moveTo
(
p0
.
dx
,
p0
.
dy
+
100
);
path
.
conicTo
(
pc
.
dx
,
pc
.
dy
+
100
,
p2
.
dx
,
p2
.
dy
+
100
,
10
);
path
.
close
();
rc
.
drawPath
(
path
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
(
0xFF404000
));
final
Path
transformedPath
=
Path
();
final
Matrix4
testMatrixTranslateRotate
=
Matrix4
.
rotationZ
(
math
.
pi
*
30.0
/
180.0
)..
translate
(
100
,
-
80
);
transformedPath
.
addPath
(
path
,
Offset
.
zero
,
matrix4:
testMatrixTranslateRotate
.
storage
);
rc
.
drawPath
(
transformedPath
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
.
fromRGBO
(
0
,
128
,
255
,
1.0
));
await
_checkScreenshot
(
rc
,
'path_transform_with_conic'
);
});
test
(
'Should draw transformed arc.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
const
double
yStart
=
20
;
final
Path
path
=
Path
();
path
.
moveTo
(
350
,
280
);
path
.
arcToPoint
(
Offset
(
450
,
90
),
radius:
Radius
.
elliptical
(
200
,
50
),
rotation:
-
math
.
pi
/
6.0
,
largeArc:
true
,
clockwise:
true
);
path
.
close
();
rc
.
drawPath
(
path
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
(
0xFF404000
));
final
Path
transformedPath
=
Path
();
final
Matrix4
testMatrixTranslateRotate
=
Matrix4
.
rotationZ
(
math
.
pi
*
30.0
/
180.0
)..
translate
(
100
,
10
);
transformedPath
.
addPath
(
path
,
Offset
.
zero
,
matrix4:
testMatrixTranslateRotate
.
storage
);
rc
.
drawPath
(
transformedPath
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
.
fromRGBO
(
0
,
128
,
255
,
1.0
));
await
_checkScreenshot
(
rc
,
'path_transform_with_arc'
);
});
test
(
'Should draw transformed rrect.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
const
double
yStart
=
20
;
final
Path
path
=
Path
();
path
.
addRRect
(
RRect
.
fromLTRBR
(
50
,
50
,
300
,
200
,
Radius
.
elliptical
(
4
,
8
)));
rc
.
drawPath
(
path
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
(
0xFF404000
));
final
Path
transformedPath
=
Path
();
final
Matrix4
testMatrixTranslateRotate
=
Matrix4
.
rotationZ
(
math
.
pi
*
30.0
/
180.0
)..
translate
(
100
,
-
80
);
transformedPath
.
addPath
(
path
,
Offset
.
zero
,
matrix4:
testMatrixTranslateRotate
.
storage
);
rc
.
drawPath
(
transformedPath
,
Paint
()
..
style
=
PaintingStyle
.
stroke
..
strokeWidth
=
2.0
..
color
=
const
Color
.
fromRGBO
(
0
,
128
,
255
,
1.0
));
await
_checkScreenshot
(
rc
,
'path_transform_with_rrect'
);
});
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录