Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_34031325
engine
提交
1bf5c8b0
E
engine
项目概览
qq_34031325
/
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,发现更多精彩内容 >>
未验证
提交
1bf5c8b0
编写于
11月 20, 2020
作者:
F
Ferhat
提交者:
GitHub
11月 20, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[web] Implement tilemode for gradient shaders. (#22597)
上级
a9f332c0
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
394 addition
and
141 deletion
+394
-141
lib/web_ui/dev/goldens_lock.yaml
lib/web_ui/dev/goldens_lock.yaml
+1
-1
lib/web_ui/lib/src/engine/canvaskit/shader.dart
lib/web_ui/lib/src/engine/canvaskit/shader.dart
+2
-2
lib/web_ui/lib/src/engine/html/render_vertices.dart
lib/web_ui/lib/src/engine/html/render_vertices.dart
+2
-2
lib/web_ui/lib/src/engine/html/shaders/shader.dart
lib/web_ui/lib/src/engine/html/shaders/shader.dart
+265
-69
lib/web_ui/lib/src/engine/util.dart
lib/web_ui/lib/src/engine/util.dart
+3
-3
lib/web_ui/lib/src/ui/painting.dart
lib/web_ui/lib/src/ui/painting.dart
+2
-1
lib/web_ui/test/golden_tests/engine/linear_gradient_golden_test.dart
...test/golden_tests/engine/linear_gradient_golden_test.dart
+66
-28
lib/web_ui/test/golden_tests/engine/radial_gradient_golden_test.dart
...test/golden_tests/engine/radial_gradient_golden_test.dart
+53
-35
未找到文件。
lib/web_ui/dev/goldens_lock.yaml
浏览文件 @
1bf5c8b0
repository
:
https://github.com/flutter/goldens.git
revision
:
67f22ef933be27ba2be8b27df1b71b2c69eb86e5
revision
:
06e0333b8371965dce5dc05e140e6dfb454f33fa
lib/web_ui/lib/src/engine/canvaskit/shader.dart
浏览文件 @
1bf5c8b0
...
...
@@ -66,7 +66,7 @@ class CkGradientLinear extends CkShader implements ui.Gradient {
assert
(
_offsetIsValid
(
to
)),
assert
(
colors
!=
null
),
// ignore: unnecessary_null_comparison
assert
(
tileMode
!=
null
),
// ignore: unnecessary_null_comparison
this
.
matrix4
=
matrix
==
null
?
null
:
_FastMatrix64
(
matrix
)
{
this
.
matrix4
=
matrix
{
if
(
assertionsEnabled
)
{
_validateColorStops
(
colors
,
colorStops
);
}
...
...
@@ -77,7 +77,7 @@ class CkGradientLinear extends CkShader implements ui.Gradient {
final
List
<
ui
.
Color
>
colors
;
final
List
<
double
>?
colorStops
;
final
ui
.
TileMode
tileMode
;
final
_FastMatrix64
?
matrix4
;
final
Float64List
?
matrix4
;
@override
SkShader
createDefault
()
{
...
...
lib/web_ui/lib/src/engine/html/render_vertices.dart
浏览文件 @
1bf5c8b0
...
...
@@ -126,7 +126,7 @@ class _WebGlRenderer implements _GlRenderer {
final
String
fragmentShader
=
_writeVerticesFragmentShader
();
_GlContext
gl
=
_GlContextCache
.
createGlContext
(
widthInPixels
,
heightInPixels
)!;
_GlProgram
glProgram
=
gl
.
useAndCacheProgram
(
vertexShader
,
fragmentShader
)
!
;
_GlProgram
glProgram
=
gl
.
useAndCacheProgram
(
vertexShader
,
fragmentShader
);
Object
transformUniform
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_ctransform'
);
...
...
@@ -487,7 +487,7 @@ class _GlContext {
left
,
top
,
_widthInPixels
,
_heightInPixels
]);
}
_GlProgram
?
useAndCacheProgram
(
_GlProgram
useAndCacheProgram
(
String
vertexShaderSource
,
String
fragmentShaderSource
)
{
String
cacheKey
=
'
$vertexShaderSource
||
$fragmentShaderSource
'
;
_GlProgram
?
cachedProgram
=
_programCache
[
cacheKey
];
...
...
lib/web_ui/lib/src/engine/html/shaders/shader.dart
浏览文件 @
1bf5c8b0
...
...
@@ -50,7 +50,7 @@ class GradientSweep extends EngineGradient {
_GlProgram
glProgram
=
gl
.
useAndCacheProgram
(
_WebGlRenderer
.
writeBaseVertexShader
(),
_createSweepFragmentShader
(
normalizedGradient
,
tileMode
))
!
;
_createSweepFragmentShader
(
normalizedGradient
,
tileMode
));
Object
tileOffset
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_tile_offset'
);
double
centerX
=
(
center
.
dx
-
shaderBounds
.
left
)
/
(
shaderBounds
.
width
);
...
...
@@ -98,34 +98,10 @@ class GradientSweep extends EngineGradient {
method
.
addStatement
(
''
'float st = angle;'
);
method
.
addStatement
(
'vec4 bias;'
);
method
.
addStatement
(
'vec4 scale;'
);
// Write uniforms for each threshold, bias and scale.
for
(
int
i
=
0
;
i
<
(
gradient
.
thresholdCount
-
1
)
~/
4
+
1
;
i
++)
{
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'threshold_
${i}
'
);
}
for
(
int
i
=
0
;
i
<
gradient
.
thresholdCount
;
i
++)
{
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'bias_
$i
'
);
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'scale_
$i
'
);
}
String
probeName
=
'st'
;
switch
(
tileMode
)
{
case
ui
.
TileMode
.
clamp
:
break
;
case
ui
.
TileMode
.
repeated
:
method
.
addStatement
(
'float tiled_st = fract(st);'
);
probeName
=
'tiled_st'
;
break
;
case
ui
.
TileMode
.
mirror
:
method
.
addStatement
(
'float t_1 = (st - 1.0);'
);
method
.
addStatement
(
'float tiled_st = abs((t_1 - 2.0 * floor(t_1 * 0.5)) - 1.0);'
);
probeName
=
'tiled_st'
;
break
;
}
_writeUnrolledBinarySearch
(
method
,
0
,
gradient
.
thresholdCount
-
1
,
probe:
probeName
,
sourcePrefix:
'threshold'
,
biasName:
'bias'
,
scaleName:
'scale'
);
final
String
probeName
=
_writeSharedGradientShader
(
builder
,
method
,
gradient
,
tileMode
);
method
.
addStatement
(
'
${fragColor.name}
=
${probeName}
* scale + bias;'
);
String
shader
=
builder
.
build
();
return
shader
;
}
...
...
@@ -140,18 +116,17 @@ class GradientSweep extends EngineGradient {
}
class
GradientLinear
extends
EngineGradient
{
GradientLinear
(
this
.
from
,
this
.
to
,
this
.
colors
,
this
.
colorStops
,
this
.
tileMode
,
Float64List
?
matrix
,
)
:
assert
(
_offsetIsValid
(
from
)),
GradientLinear
(
this
.
from
,
this
.
to
,
this
.
colors
,
this
.
colorStops
,
this
.
tileMode
,
Float32List
?
matrix
,)
:
assert
(
_offsetIsValid
(
from
)),
assert
(
_offsetIsValid
(
to
)),
assert
(
colors
!=
null
),
// ignore: unnecessary_null_comparison
assert
(
tileMode
!=
null
),
// ignore: unnecessary_null_comparison
this
.
matrix4
=
matrix
==
null
?
null
:
_FastMatrix
64
(
matrix
),
this
.
matrix4
=
matrix
==
null
?
null
:
_FastMatrix
32
(
matrix
),
super
.
_
()
{
if
(
assertionsEnabled
)
{
_validateColorStops
(
colors
,
colorStops
);
...
...
@@ -163,12 +138,22 @@ class GradientLinear extends EngineGradient {
final
List
<
ui
.
Color
>
colors
;
final
List
<
double
>?
colorStops
;
final
ui
.
TileMode
tileMode
;
final
_FastMatrix
64
?
matrix4
;
final
_FastMatrix
32
?
matrix4
;
@override
html
.
CanvasGradient
createPaintStyle
(
html
.
CanvasRenderingContext2D
?
ctx
,
Object
createPaintStyle
(
html
.
CanvasRenderingContext2D
?
ctx
,
ui
.
Rect
?
shaderBounds
,
double
density
)
{
if
(
tileMode
==
ui
.
TileMode
.
clamp
)
{
return
_createCanvasGradient
(
ctx
,
shaderBounds
,
density
);
}
else
{
initWebGl
();
return
_createGlGradient
(
ctx
,
shaderBounds
,
density
);
}
}
html
.
CanvasGradient
_createCanvasGradient
(
html
.
CanvasRenderingContext2D
?
ctx
,
ui
.
Rect
?
shaderBounds
,
double
density
)
{
_FastMatrix
64
?
matrix4
=
this
.
matrix4
;
_FastMatrix
32
?
matrix4
=
this
.
matrix4
;
html
.
CanvasGradient
gradient
;
final
double
offsetX
=
shaderBounds
!.
left
;
final
double
offsetY
=
shaderBounds
.
top
;
...
...
@@ -180,29 +165,175 @@ class GradientLinear extends EngineGradient {
final
double
fromY
=
matrix4
.
transformedY
+
centerY
;
matrix4
.
transform
(
to
.
dx
-
centerX
,
to
.
dy
-
centerY
);
gradient
=
ctx
!.
createLinearGradient
(
fromX
-
offsetX
,
fromY
-
offsetY
,
matrix4
.
transformedX
+
centerX
-
offsetX
,
matrix4
.
transformedY
-
offsetY
+
centerY
);
matrix4
.
transformedX
+
centerX
-
offsetX
,
matrix4
.
transformedY
-
offsetY
+
centerY
);
}
else
{
gradient
=
ctx
!.
createLinearGradient
(
from
.
dx
-
offsetX
,
from
.
dy
-
offsetY
,
to
.
dx
-
offsetX
,
to
.
dy
-
offsetY
);
gradient
=
ctx
!.
createLinearGradient
(
from
.
dx
-
offsetX
,
from
.
dy
-
offsetY
,
to
.
dx
-
offsetX
,
to
.
dy
-
offsetY
);
}
_addColorStopsToCanvasGradient
(
gradient
,
colors
,
colorStops
);
return
gradient
;
}
/// Creates a linear gradient with tiling repeat or mirror.
html
.
CanvasPattern
_createGlGradient
(
html
.
CanvasRenderingContext2D
?
ctx
,
ui
.
Rect
?
shaderBounds
,
double
density
)
{
assert
(
shaderBounds
!=
null
);
int
widthInPixels
=
shaderBounds
!.
width
.
ceil
();
int
heightInPixels
=
shaderBounds
.
height
.
ceil
();
assert
(
widthInPixels
>
0
&&
heightInPixels
>
0
);
// Render gradient into a bitmap and create a canvas pattern.
_OffScreenCanvas
offScreenCanvas
=
_OffScreenCanvas
(
widthInPixels
,
heightInPixels
);
_GlContext
gl
=
_OffScreenCanvas
.
supported
?
_GlContext
.
fromOffscreenCanvas
(
offScreenCanvas
.
_canvas
!)
:
_GlContext
.
fromCanvas
(
offScreenCanvas
.
_glCanvas
!,
webGLVersion
==
WebGLVersion
.
webgl1
);
gl
.
setViewportSize
(
widthInPixels
,
heightInPixels
);
NormalizedGradient
normalizedGradient
=
NormalizedGradient
(
colors
,
stops:
colorStops
);
_GlProgram
glProgram
=
gl
.
useAndCacheProgram
(
_WebGlRenderer
.
writeBaseVertexShader
(),
_createLinearFragmentShader
(
normalizedGradient
,
tileMode
));
final
List
<
double
>?
colorStops
=
this
.
colorStops
;
if
(
colorStops
==
null
)
{
assert
(
colors
.
length
==
2
);
gradient
.
addColorStop
(
0
,
colorToCssString
(
colors
[
0
])!);
gradient
.
addColorStop
(
1
,
colorToCssString
(
colors
[
1
])!);
return
gradient
;
// Setup from/to uniforms.
//
// To compute t value between 0..1 for any point on the screen,
// we need to use from,to point pair to construct a matrix that will
// take any fragment coordinate and transform it to a t value.
//
// We compute the matrix by:
// 1- Shift from,to vector to origin.
// 2- Rotate the vector to align with x axis.
// 3- Scale it to unit vector.
double
dx
=
to
.
dx
-
from
.
dx
;
double
dy
=
to
.
dy
-
from
.
dy
;
double
length
=
math
.
sqrt
(
dx
*
dx
+
dy
*
dy
);
// sin(theta) = dy / length.
// cos(theta) = dx / length.
// Flip dy for gl flip.
double
sinVal
=
length
<
kFltEpsilon
?
0
:
-
dy
/
length
;
double
cosVal
=
length
<
kFltEpsilon
?
1
:
dx
/
length
;
final
Matrix4
translateToOrigin
=
matrix4
==
null
?
Matrix4
.
translationValues
(-
from
.
dx
,
-
from
.
dy
,
0
)
:
Matrix4
.
fromFloat32List
(
matrix4
!.
matrix
)
..
translate
(-
from
.
dx
,
-
from
.
dy
);
// Rotate around Z axis.
final
Matrix4
rotationZ
=
Matrix4
.
identity
();
final
Float32List
storage
=
rotationZ
.
storage
;
storage
[
0
]
=
cosVal
;
storage
[
1
]
=
-
sinVal
;
storage
[
4
]
=
sinVal
;
storage
[
5
]
=
cosVal
;
Matrix4
gradientTransform
=
Matrix4
.
identity
();
if
(
length
>
kFltEpsilon
)
{
gradientTransform
.
scale
(
1.0
/
length
);
}
gradientTransform
.
multiply
(
rotationZ
);
gradientTransform
.
multiply
(
translateToOrigin
);
// Setup gradient uniforms for t search.
normalizedGradient
.
setupUniforms
(
gl
,
glProgram
);
// Setup matrix transform uniform.
Object
gradientMatrix
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'm_gradient'
);
gl
.
setUniformMatrix4fv
(
gradientMatrix
,
false
,
gradientTransform
.
storage
);
Object
uRes
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_resolution'
);
gl
.
setUniform2f
(
uRes
,
widthInPixels
.
toDouble
(),
heightInPixels
.
toDouble
());
// Draw gradient and convert to pattern.
Object
?
imageBitmap
=
_glRenderer
!.
drawRect
(
ui
.
Rect
.
fromLTWH
(
0
,
0
,
shaderBounds
.
width
,
shaderBounds
.
height
)
/* !! shaderBounds */
,
gl
,
glProgram
,
normalizedGradient
,
widthInPixels
,
heightInPixels
,
);
return
ctx
!.
createPattern
(
imageBitmap
!,
'no-repeat'
)!;
}
String
_createLinearFragmentShader
(
NormalizedGradient
gradient
,
ui
.
TileMode
tileMode
)
{
ShaderBuilder
builder
=
ShaderBuilder
.
fragment
(
webGLVersion
);
builder
.
floatPrecision
=
ShaderPrecision
.
kMedium
;
builder
.
addIn
(
ShaderType
.
kVec4
,
name:
'v_color'
);
builder
.
addUniform
(
ShaderType
.
kVec2
,
name:
'u_resolution'
);
builder
.
addUniform
(
ShaderType
.
kMat4
,
name:
'm_gradient'
);
ShaderDeclaration
fragColor
=
builder
.
fragmentColor
;
ShaderMethod
method
=
builder
.
addMethod
(
'main'
);
// Linear gradient.
// Multiply with m_gradient transform to convert from fragment coordinate to
// distance on the from-to line.
method
.
addStatement
(
'vec4 localCoord = vec4(gl_FragCoord.x, '
'u_resolution.y - gl_FragCoord.y, 0, 1) * m_gradient;'
);
method
.
addStatement
(
'float st = localCoord.x;'
);
final
String
probeName
=
_writeSharedGradientShader
(
builder
,
method
,
gradient
,
tileMode
);
method
.
addStatement
(
'
${fragColor.name}
=
${probeName}
* scale + bias;'
);
String
shader
=
builder
.
build
();
return
shader
;
}
}
void
_addColorStopsToCanvasGradient
(
html
.
CanvasGradient
gradient
,
List
<
ui
.
Color
>
colors
,
List
<
double
>?
colorStops
)
{
if
(
colorStops
==
null
)
{
assert
(
colors
.
length
==
2
);
gradient
.
addColorStop
(
0
,
colorToCssString
(
colors
[
0
])!);
gradient
.
addColorStop
(
1
,
colorToCssString
(
colors
[
1
])!);
}
else
{
for
(
int
i
=
0
;
i
<
colors
.
length
;
i
++)
{
gradient
.
addColorStop
(
colorStops
[
i
],
colorToCssString
(
colors
[
i
])!);
}
return
gradient
;
}
}
// TODO(flutter_web): For transforms and tile modes implement as webgl
// For now only GradientRotation is supported in flutter which is implemented
// for linear gradient.
// See https://github.com/flutter/flutter/issues/32819
/// Writes shader code to map fragment value to gradient color.
///
/// Returns name of gradient treshold variable to use to compute color.
String
_writeSharedGradientShader
(
ShaderBuilder
builder
,
ShaderMethod
method
,
NormalizedGradient
gradient
,
ui
.
TileMode
tileMode
)
{
method
.
addStatement
(
'vec4 bias;'
);
method
.
addStatement
(
'vec4 scale;'
);
// Write uniforms for each threshold, bias and scale.
for
(
int
i
=
0
;
i
<
(
gradient
.
thresholdCount
-
1
)
~/
4
+
1
;
i
++)
{
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'threshold_
${i}
'
);
}
for
(
int
i
=
0
;
i
<
gradient
.
thresholdCount
;
i
++)
{
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'bias_
$i
'
);
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'scale_
$i
'
);
}
// Use st variable name if clamped, otherwise write code to comnpute
// tiled_st.
String
probeName
=
'st'
;
switch
(
tileMode
)
{
case
ui
.
TileMode
.
clamp
:
break
;
case
ui
.
TileMode
.
repeated
:
method
.
addStatement
(
'float tiled_st = fract(st);'
);
probeName
=
'tiled_st'
;
break
;
case
ui
.
TileMode
.
mirror
:
method
.
addStatement
(
'float t_1 = (st - 1.0);'
);
method
.
addStatement
(
'float tiled_st = abs((t_1 - 2.0 * floor(t_1 * 0.5)) - 1.0);'
);
probeName
=
'tiled_st'
;
break
;
}
_writeUnrolledBinarySearch
(
method
,
0
,
gradient
.
thresholdCount
-
1
,
probe:
probeName
,
sourcePrefix:
'threshold'
,
biasName:
'bias'
,
scaleName:
'scale'
);
return
probeName
;
}
class
GradientRadial
extends
EngineGradient
{
GradientRadial
(
this
.
center
,
this
.
radius
,
this
.
colors
,
this
.
colorStops
,
this
.
tileMode
,
this
.
matrix4
)
...
...
@@ -218,30 +349,95 @@ class GradientRadial extends EngineGradient {
@override
Object
createPaintStyle
(
html
.
CanvasRenderingContext2D
?
ctx
,
ui
.
Rect
?
shaderBounds
,
double
density
)
{
if
(
!
useCanvasKit
)
{
if
(
tileMode
!=
ui
.
TileMode
.
clamp
)
{
throw
UnimplementedError
(
'TileMode not supported in GradientRadial shader'
);
}
if
(
tileMode
==
ui
.
TileMode
.
clamp
)
{
return
_createCanvasGradient
(
ctx
,
shaderBounds
,
density
);
}
else
{
initWebGl
(
);
return
_createGlGradient
(
ctx
,
shaderBounds
,
density
);
}
}
Object
_createCanvasGradient
(
html
.
CanvasRenderingContext2D
?
ctx
,
ui
.
Rect
?
shaderBounds
,
double
density
)
{
final
double
offsetX
=
shaderBounds
!.
left
;
final
double
offsetY
=
shaderBounds
.
top
;
final
html
.
CanvasGradient
gradient
=
ctx
!.
createRadialGradient
(
center
.
dx
-
offsetX
,
center
.
dy
-
offsetY
,
0
,
center
.
dx
-
offsetX
,
center
.
dy
-
offsetY
,
radius
);
final
List
<
double
>?
colorStops
=
this
.
colorStops
;
if
(
colorStops
==
null
)
{
assert
(
colors
.
length
==
2
);
gradient
.
addColorStop
(
0
,
colorToCssString
(
colors
[
0
])!);
gradient
.
addColorStop
(
1
,
colorToCssString
(
colors
[
1
])!);
return
gradient
;
}
else
{
for
(
int
i
=
0
;
i
<
colors
.
length
;
i
++)
{
gradient
.
addColorStop
(
colorStops
[
i
],
colorToCssString
(
colors
[
i
])!);
}
}
_addColorStopsToCanvasGradient
(
gradient
,
colors
,
colorStops
);
return
gradient
;
}
/// Creates a radial gradient with tiling repeat or mirror.
html
.
CanvasPattern
_createGlGradient
(
html
.
CanvasRenderingContext2D
?
ctx
,
ui
.
Rect
?
shaderBounds
,
double
density
)
{
assert
(
shaderBounds
!=
null
);
int
widthInPixels
=
shaderBounds
!.
width
.
ceil
();
int
heightInPixels
=
shaderBounds
.
height
.
ceil
();
assert
(
widthInPixels
>
0
&&
heightInPixels
>
0
);
initWebGl
();
// Render gradient into a bitmap and create a canvas pattern.
_OffScreenCanvas
offScreenCanvas
=
_OffScreenCanvas
(
widthInPixels
,
heightInPixels
);
_GlContext
gl
=
_OffScreenCanvas
.
supported
?
_GlContext
.
fromOffscreenCanvas
(
offScreenCanvas
.
_canvas
!)
:
_GlContext
.
fromCanvas
(
offScreenCanvas
.
_glCanvas
!,
webGLVersion
==
WebGLVersion
.
webgl1
);
gl
.
setViewportSize
(
widthInPixels
,
heightInPixels
);
NormalizedGradient
normalizedGradient
=
NormalizedGradient
(
colors
,
stops:
colorStops
);
_GlProgram
glProgram
=
gl
.
useAndCacheProgram
(
_WebGlRenderer
.
writeBaseVertexShader
(),
_createRadialFragmentShader
(
normalizedGradient
,
tileMode
));
Object
tileOffset
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_tile_offset'
);
double
centerX
=
(
center
.
dx
-
shaderBounds
.
left
)
/
(
shaderBounds
.
width
);
double
centerY
=
(
center
.
dy
-
shaderBounds
.
top
)
/
(
shaderBounds
.
height
);
gl
.
setUniform2f
(
tileOffset
,
2
*
(
shaderBounds
.
width
*
(
centerX
-
0.5
)),
2
*
(
shaderBounds
.
height
*
(
centerY
-
0.5
)));
Object
radiusUniform
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_radius'
);
gl
.
setUniform1f
(
radiusUniform
,
radius
);
normalizedGradient
.
setupUniforms
(
gl
,
glProgram
);
Object
gradientMatrix
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'm_gradient'
);
gl
.
setUniformMatrix4fv
(
gradientMatrix
,
false
,
matrix4
==
null
?
Matrix4
.
identity
().
storage
:
matrix4
!);
Object
?
imageBitmap
=
_glRenderer
!.
drawRect
(
ui
.
Rect
.
fromLTWH
(
0
,
0
,
shaderBounds
.
width
,
shaderBounds
.
height
),
gl
,
glProgram
,
normalizedGradient
,
widthInPixels
,
heightInPixels
);
return
ctx
!.
createPattern
(
imageBitmap
!,
'no-repeat'
)!;
}
String
_createRadialFragmentShader
(
NormalizedGradient
gradient
,
ui
.
TileMode
tileMode
)
{
ShaderBuilder
builder
=
ShaderBuilder
.
fragment
(
webGLVersion
);
builder
.
floatPrecision
=
ShaderPrecision
.
kMedium
;
builder
.
addIn
(
ShaderType
.
kVec4
,
name:
'v_color'
);
builder
.
addUniform
(
ShaderType
.
kVec2
,
name:
'u_resolution'
);
builder
.
addUniform
(
ShaderType
.
kVec2
,
name:
'u_tile_offset'
);
builder
.
addUniform
(
ShaderType
.
kFloat
,
name:
'u_radius'
);
builder
.
addUniform
(
ShaderType
.
kMat4
,
name:
'm_gradient'
);
ShaderDeclaration
fragColor
=
builder
.
fragmentColor
;
ShaderMethod
method
=
builder
.
addMethod
(
'main'
);
// Sweep gradient
method
.
addStatement
(
'vec2 center = 0.5 * (u_resolution + u_tile_offset);'
);
method
.
addStatement
(
'vec4 localCoord = vec4(gl_FragCoord.x - center.x, center.y - gl_FragCoord.y, 0, 1) * m_gradient;'
);
method
.
addStatement
(
'float dist = length(localCoord);'
);
method
.
addStatement
(
''
'float st = abs(dist / u_radius);'
);
final
String
probeName
=
_writeSharedGradientShader
(
builder
,
method
,
gradient
,
tileMode
);
method
.
addStatement
(
'
${fragColor.name}
=
${probeName}
* scale + bias;'
);
String
shader
=
builder
.
build
();
return
shader
;
}
}
class
GradientConical
extends
EngineGradient
{
...
...
lib/web_ui/lib/src/engine/util.dart
浏览文件 @
1bf5c8b0
...
...
@@ -526,10 +526,10 @@ FutureOr<void> sendFontChangeMessage() async {
}
// Stores matrix in a form that allows zero allocation transforms.
class
_FastMatrix
64
{
final
Float
64
List
matrix
;
class
_FastMatrix
32
{
final
Float
32
List
matrix
;
double
transformedX
=
0
,
transformedY
=
0
;
_FastMatrix
64
(
this
.
matrix
);
_FastMatrix
32
(
this
.
matrix
);
void
transform
(
double
x
,
double
y
)
{
transformedX
=
matrix
[
12
]
+
(
matrix
[
0
]
*
x
)
+
(
matrix
[
4
]
*
y
);
...
...
lib/web_ui/lib/src/ui/painting.dart
浏览文件 @
1bf5c8b0
...
...
@@ -280,7 +280,8 @@ abstract class Gradient extends Shader {
Float64List
?
matrix4
,
])
=>
engine
.
useCanvasKit
?
engine
.
CkGradientLinear
(
from
,
to
,
colors
,
colorStops
,
tileMode
,
matrix4
)
:
engine
.
GradientLinear
(
from
,
to
,
colors
,
colorStops
,
tileMode
,
matrix4
);
:
engine
.
GradientLinear
(
from
,
to
,
colors
,
colorStops
,
tileMode
,
matrix4
==
null
?
null
:
engine
.
toMatrix32
(
matrix4
));
factory
Gradient
.
radial
(
Offset
center
,
double
radius
,
...
...
lib/web_ui/test/golden_tests/engine/linear_gradient_golden_test.dart
浏览文件 @
1bf5c8b0
...
...
@@ -3,45 +3,23 @@
// found in the LICENSE file.
// @dart = 2.6
import
'dart:html'
as
html
;
import
'dart:math'
as
math
;
import
'package:test/bootstrap/browser.dart'
;
import
'package:test/test.dart'
;
import
'package:ui/ui.dart'
hide
TextStyle
;
import
'package:ui/src/engine.dart'
;
import
'package:web_engine_tester/golden_tester.dart'
;
import
'screenshot.dart'
;
void
main
(
)
{
internalBootstrapBrowserTest
(()
=>
testMain
);
}
void
testMain
(
)
async
{
const
double
screenWidth
=
6
00.0
;
const
double
screenHeight
=
8
00.0
;
const
double
screenWidth
=
5
00.0
;
const
double
screenHeight
=
5
00.0
;
const
Rect
screenRect
=
Rect
.
fromLTWH
(
0
,
0
,
screenWidth
,
screenHeight
);
// 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
)})
async
{
final
EngineCanvas
engineCanvas
=
BitmapCanvas
(
screenRect
);
rc
.
endRecording
();
rc
.
apply
(
engineCanvas
,
screenRect
);
// 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
// golden screenshot.
sceneElement
.
remove
();
}
}
setUp
(()
async
{
debugEmulateFlutterTesterEnvironment
=
true
;
await
webOnlyInitializePlatform
();
...
...
@@ -59,7 +37,9 @@ void testMain() async {
[
Color
(
0xFFcfdfd2
),
Color
(
0xFF042a85
)]);
rc
.
drawRect
(
shaderRect
,
paint
);
expect
(
rc
.
hasArbitraryPaint
,
isTrue
);
await
_checkScreenshot
(
rc
,
'linear_gradient_rect'
);
await
canvasScreenshot
(
rc
,
'linear_gradient_rect'
,
region:
screenRect
,
maxDiffRatePercent:
0.01
);
});
test
(
'Should draw linear gradient with transform.'
,
()
async
{
...
...
@@ -85,7 +65,9 @@ void testMain() async {
yOffset
+=
120
;
}
expect
(
rc
.
hasArbitraryPaint
,
isTrue
);
await
_checkScreenshot
(
rc
,
'linear_gradient_oval_matrix'
);
await
canvasScreenshot
(
rc
,
'linear_gradient_oval_matrix'
,
region:
screenRect
,
maxDiffRatePercent:
0.2
);
});
// Regression test for https://github.com/flutter/flutter/issues/50010
...
...
@@ -99,6 +81,62 @@ void testMain() async {
[
Color
(
0xFFcfdfd2
),
Color
(
0xFF042a85
)]);
rc
.
drawRRect
(
RRect
.
fromRectAndRadius
(
shaderRect
,
Radius
.
circular
(
16
)),
paint
);
expect
(
rc
.
hasArbitraryPaint
,
isTrue
);
await
_checkScreenshot
(
rc
,
'linear_gradient_rounded_rect'
);
await
canvasScreenshot
(
rc
,
'linear_gradient_rounded_rect'
,
region:
screenRect
,
maxDiffRatePercent:
0.1
);
});
test
(
'Should draw tiled repeated linear gradient with transform.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
List
<
double
>
angles
=
[
0.0
,
30.0
,
210.0
];
double
yOffset
=
0
;
for
(
double
angle
in
angles
)
{
final
Rect
shaderRect
=
Rect
.
fromLTWH
(
50
,
50
+
yOffset
,
100
,
100
);
final
Paint
paint
=
Paint
()
..
shader
=
Gradient
.
linear
(
Offset
(
shaderRect
.
left
,
shaderRect
.
top
),
Offset
(
shaderRect
.
left
+
shaderRect
.
width
/
2
,
shaderRect
.
top
),
[
Color
(
0xFFFF0000
),
Color
(
0xFF042a85
)],
null
,
TileMode
.
repeated
,
Matrix4
.
rotationZ
((
angle
/
180
)
*
math
.
pi
)
.
toFloat64
());
rc
.
drawRect
(
shaderRect
,
Paint
()
..
color
=
Color
(
0xFF000000
));
rc
.
drawOval
(
shaderRect
,
paint
);
yOffset
+=
120
;
}
expect
(
rc
.
hasArbitraryPaint
,
isTrue
);
await
canvasScreenshot
(
rc
,
'linear_gradient_tiled_repeated_rect'
,
region:
screenRect
);
});
test
(
'Should draw tiled mirrored linear gradient with transform.'
,
()
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
List
<
double
>
angles
=
[
0.0
,
30.0
,
210.0
];
double
yOffset
=
0
;
for
(
double
angle
in
angles
)
{
final
Rect
shaderRect
=
Rect
.
fromLTWH
(
50
,
50
+
yOffset
,
100
,
100
);
final
Paint
paint
=
Paint
()
..
shader
=
Gradient
.
linear
(
Offset
(
shaderRect
.
left
,
shaderRect
.
top
),
Offset
(
shaderRect
.
left
+
shaderRect
.
width
/
2
,
shaderRect
.
top
),
[
Color
(
0xFFFF0000
),
Color
(
0xFF042a85
)],
null
,
TileMode
.
mirror
,
Matrix4
.
rotationZ
((
angle
/
180
)
*
math
.
pi
)
.
toFloat64
());
rc
.
drawRect
(
shaderRect
,
Paint
()
..
color
=
Color
(
0xFF000000
));
rc
.
drawOval
(
shaderRect
,
paint
);
yOffset
+=
120
;
}
expect
(
rc
.
hasArbitraryPaint
,
isTrue
);
await
canvasScreenshot
(
rc
,
'linear_gradient_tiled_mirrored_rect'
,
region:
screenRect
);
});
}
lib/web_ui/test/golden_tests/engine/radial_gradient_golden_test.dart
浏览文件 @
1bf5c8b0
...
...
@@ -3,44 +3,17 @@
// found in the LICENSE file.
// @dart = 2.6
import
'dart:html'
as
html
;
import
'package:test/bootstrap/browser.dart'
;
import
'package:test/test.dart'
;
import
'package:ui/ui.dart'
hide
TextStyle
;
import
'package:ui/src/engine.dart'
;
import
'package:web_engine_tester/golden_tester.dart'
;
import
'screenshot.dart'
;
void
main
(
)
{
internalBootstrapBrowserTest
(()
=>
testMain
);
}
void
testMain
(
)
async
{
const
double
screenWidth
=
600.0
;
const
double
screenHeight
=
800.0
;
const
Rect
screenRect
=
Rect
.
fromLTWH
(
0
,
0
,
screenWidth
,
screenHeight
);
// 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
.
endRecording
();
rc
.
apply
(
engineCanvas
,
screenRect
);
// 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
,
write:
write
);
}
finally
{
// The page is reused across tests, so remove the element after taking the
// golden screenshot.
sceneElement
.
remove
();
}
}
setUp
(()
async
{
debugEmulateFlutterTesterEnvironment
=
true
;
...
...
@@ -51,14 +24,17 @@ void testMain() async {
Future
<
void
>
_testGradient
(
String
fileName
,
Shader
shader
,
{
Rect
paintRect
=
const
Rect
.
fromLTRB
(
50
,
50
,
300
,
300
),
Rect
shaderRect
=
const
Rect
.
fromLTRB
(
50
,
50
,
300
,
300
)})
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
Rect
shaderRect
=
const
Rect
.
fromLTRB
(
50
,
50
,
300
,
300
),
bool
write
=
false
,
double
maxDiffRatePercent
=
0
,
Rect
region
=
const
Rect
.
fromLTWH
(
0
,
0
,
500
,
500
)})
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
region
);
final
Paint
paint
=
Paint
()..
shader
=
shader
;
final
Path
path
=
Path
();
path
.
addRect
(
paintRect
);
rc
.
drawPath
(
path
,
paint
);
await
_checkScreenshot
(
rc
,
fileName
);
await
canvasScreenshot
(
rc
,
fileName
,
write:
write
,
region:
region
,
maxDiffRatePercent:
maxDiffRatePercent
);
}
test
(
'Should draw centered radial gradient.'
,
()
async
{
...
...
@@ -73,7 +49,8 @@ void testMain() async {
const
Color
.
fromARGB
(
255
,
0
,
0
,
0
),
const
Color
.
fromARGB
(
255
,
0
,
0
,
255
)
]),
shaderRect:
shaderRect
);
shaderRect:
shaderRect
,
maxDiffRatePercent:
0.2
);
});
test
(
'Should draw right bottom centered radial gradient.'
,
()
async
{
...
...
@@ -85,7 +62,8 @@ void testMain() async {
const
Color
.
fromARGB
(
255
,
0
,
0
,
0
),
const
Color
.
fromARGB
(
255
,
0
,
0
,
255
)
]),
shaderRect:
shaderRect
);
shaderRect:
shaderRect
,
maxDiffRatePercent:
0.3
);
});
test
(
'Should draw with radial gradient with TileMode.clamp.'
,
()
async
{
...
...
@@ -102,6 +80,46 @@ void testMain() async {
],
<
double
>[
0.0
,
1.0
],
TileMode
.
clamp
),
shaderRect:
shaderRect
);
shaderRect:
shaderRect
,
maxDiffRatePercent:
0.2
);
});
const
List
<
Color
>
colors
=
<
Color
>[
Color
(
0xFF000000
),
Color
(
0xFFFF3C38
),
Color
(
0xFFFF8C42
),
Color
(
0xFFFFF275
),
Color
(
0xFF6699CC
),
Color
(
0xFF656D78
),];
const
List
<
double
>
colorStops
=
<
double
>[
0.0
,
0.05
,
0.4
,
0.6
,
0.9
,
1.0
];
test
(
'Should draw with radial gradient with TileMode.repeated.'
,
()
async
{
Rect
shaderRect
=
const
Rect
.
fromLTRB
(
50
,
50
,
100
,
100
);
await
_testGradient
(
'radial_gradient_tilemode_repeated'
,
Gradient
.
radial
(
Offset
((
shaderRect
.
left
+
shaderRect
.
right
)
/
2
,
(
shaderRect
.
top
+
shaderRect
.
bottom
)
/
2
),
shaderRect
.
width
/
2
,
colors
,
colorStops
,
TileMode
.
repeated
),
shaderRect:
shaderRect
,
region:
const
Rect
.
fromLTWH
(
0
,
0
,
600
,
800
));
});
test
(
'Should draw with radial gradient with TileMode.mirrored.'
,
()
async
{
Rect
shaderRect
=
const
Rect
.
fromLTRB
(
50
,
50
,
100
,
100
);
await
_testGradient
(
'radial_gradient_tilemode_mirror'
,
Gradient
.
radial
(
Offset
((
shaderRect
.
left
+
shaderRect
.
right
)
/
2
,
(
shaderRect
.
top
+
shaderRect
.
bottom
)
/
2
),
shaderRect
.
width
/
2
,
colors
,
colorStops
,
TileMode
.
mirror
),
shaderRect:
shaderRect
,
region:
const
Rect
.
fromLTWH
(
0
,
0
,
600
,
800
));
});
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录