mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
soften shadows even more; fix shadow alpha (#18029)
* soften shadows even more; fix shadow alpha
This commit is contained in:
parent
32a4cc5ed4
commit
590381a00a
@ -1,2 +1,2 @@
|
||||
repository: https://github.com/flutter/goldens.git
|
||||
revision: 263d816b73df47fca2fdc0fbce7ad09f17aa30b6
|
||||
revision: f64d8957ae281d1558647f0591ff9742e6135385
|
||||
|
||||
@ -598,7 +598,21 @@ class _CanvasPool extends _SaveStackTracking {
|
||||
bool transparentOccluder) {
|
||||
final SurfaceShadowData shadow = computeShadow(path.getBounds(), elevation);
|
||||
if (shadow != null) {
|
||||
// TODO(het): Shadows with transparent occluders are not supported
|
||||
// On April 2020 Web canvas 2D did not support shadow color alpha. So
|
||||
// instead we apply alpha separately using globalAlpha, then paint a
|
||||
// solid shadow.
|
||||
final ui.Color shadowColor = toShadowColor(color);
|
||||
final double opacity = shadowColor.alpha / 255;
|
||||
final String solidColor = colorComponentsToCssString(
|
||||
shadowColor.red,
|
||||
shadowColor.green,
|
||||
shadowColor.blue,
|
||||
255,
|
||||
);
|
||||
context.save();
|
||||
context.globalAlpha = opacity;
|
||||
|
||||
// TODO(hterkelsen): Shadows with transparent occluders are not supported
|
||||
// on webkit since filter is unsupported.
|
||||
if (transparentOccluder && browserEngine != BrowserEngine.webkit) {
|
||||
// We paint shadows using a path and a mask filter instead of the
|
||||
@ -607,17 +621,17 @@ class _CanvasPool extends _SaveStackTracking {
|
||||
// paint the shadow without the path itself, but if we use a non-zero
|
||||
// alpha for the paint the path is painted in addition to the shadow,
|
||||
// which is undesirable.
|
||||
context.save();
|
||||
context.translate(shadow.offset.dx, shadow.offset.dy);
|
||||
context.filter = _maskFilterToCss(
|
||||
ui.MaskFilter.blur(ui.BlurStyle.normal, shadow.blurWidth));
|
||||
context.strokeStyle = '';
|
||||
context.fillStyle = colorToCssString(color);
|
||||
_runPath(context, path);
|
||||
context.fill();
|
||||
context.restore();
|
||||
context.fillStyle = solidColor;
|
||||
} else {
|
||||
// TODO(het): We fill the path with this paint, then later we clip
|
||||
// TODO(yjbanov): the following comment by hterkelsen makes sense, but
|
||||
// somehow we lost the implementation described in it.
|
||||
// Perhaps we should revisit this and actually do what
|
||||
// the comment says.
|
||||
// TODO(hterkelsen): We fill the path with this paint, then later we clip
|
||||
// by the same path and fill it with a fully opaque color (we know
|
||||
// the color is fully opaque because `transparentOccluder` is false.
|
||||
// However, due to anti-aliasing of the clip, a few pixels of the
|
||||
@ -625,23 +639,20 @@ class _CanvasPool extends _SaveStackTracking {
|
||||
// the opaque occluder. For that reason, we fill with the shadow color,
|
||||
// and set the shadow color to fully opaque. This way, the visible
|
||||
// pixels are less opaque and less noticeable.
|
||||
context.save();
|
||||
context.filter = 'none';
|
||||
context.strokeStyle = '';
|
||||
final int red = color.red;
|
||||
final int green = color.green;
|
||||
final int blue = color.blue;
|
||||
// Multiply by 0.4 to make shadows less aggressive (https://github.com/flutter/flutter/issues/52734)
|
||||
final int alpha = (0.4 * color.alpha).round();
|
||||
context.fillStyle = colorComponentsToCssString(red, green, blue, alpha);
|
||||
context.fillStyle = solidColor;
|
||||
context.shadowBlur = shadow.blurWidth;
|
||||
context.shadowColor = colorToCssString(color.withAlpha(0xff));
|
||||
context.shadowColor = solidColor;
|
||||
context.shadowOffsetX = shadow.offset.dx;
|
||||
context.shadowOffsetY = shadow.offset.dy;
|
||||
_runPath(context, path);
|
||||
context.fill();
|
||||
context.restore();
|
||||
}
|
||||
_runPath(context, path);
|
||||
context.fill();
|
||||
|
||||
// This also resets globalAlpha and shadow attributes. See:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save#Drawing_state
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -133,9 +133,24 @@ void applyCssShadow(
|
||||
if (shadow == null) {
|
||||
element.style.boxShadow = 'none';
|
||||
} else {
|
||||
// Multiply by 0.4 to make shadows less aggressive (https://github.com/flutter/flutter/issues/52734)
|
||||
final double alpha = 0.4 * color.alpha / 255;
|
||||
color = toShadowColor(color);
|
||||
element.style.boxShadow = '${shadow.offset.dx}px ${shadow.offset.dy}px '
|
||||
'${shadow.blurWidth}px 0px rgba(${color.red}, ${color.green}, ${color.blue}, $alpha)';
|
||||
'${shadow.blurWidth}px 0px rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha / 255})';
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a shadow color specified by the framework to the color that should
|
||||
/// actually be applied when rendering the shadow.
|
||||
///
|
||||
/// Flutter shadows look softer than the color specified by the developer. For
|
||||
/// example, it is common to get a solid black for a shadow and see a very soft
|
||||
/// shadow. This function softens the color by reducing its alpha by a constant
|
||||
/// factor.
|
||||
ui.Color toShadowColor(ui.Color color) {
|
||||
// Reduce alpha to make shadows less aggressive:
|
||||
//
|
||||
// - https://github.com/flutter/flutter/issues/52734
|
||||
// - https://github.com/flutter/gallery/issues/118
|
||||
final int reducedAlpha = (0.3 * color.alpha).round();
|
||||
return ui.Color((reducedAlpha & 0xff) << 24 | (color.value & 0x00ffffff));
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ void main() async {
|
||||
builder.pop(); // offset
|
||||
}
|
||||
|
||||
void _paintBitmapCanvasShadow(double elevation, Offset offset) {
|
||||
void _paintBitmapCanvasShadow(double elevation, Offset offset, bool transparentOccluder) {
|
||||
final SurfacePath path = SurfacePath()
|
||||
..addRect(const Rect.fromLTRB(0, 0, 20, 20));
|
||||
builder.pushOffset(offset.dx, offset.dy);
|
||||
@ -82,7 +82,7 @@ void main() async {
|
||||
path,
|
||||
_kShadowColor,
|
||||
elevation,
|
||||
false,
|
||||
transparentOccluder,
|
||||
);
|
||||
builder.addPicture(Offset.zero, recorder.endRecording());
|
||||
_paintShapeOutline();
|
||||
@ -136,12 +136,16 @@ void main() async {
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_paintBitmapCanvasShadow(i.toDouble(), Offset(50.0 * i, 60));
|
||||
_paintBitmapCanvasShadow(i.toDouble(), Offset(50.0 * i, 60), false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_paintBitmapCanvasShadow(i.toDouble(), Offset(50.0 * i, 120), true);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_paintBitmapCanvasComplexPathShadow(
|
||||
i.toDouble(), Offset(50.0 * i, 120));
|
||||
i.toDouble(), Offset(50.0 * i, 180));
|
||||
}
|
||||
|
||||
builder.pop();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user