blob: 3906e7d70175a24c163d15986282a04e70c98cf2 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/controls/gradient_layer_delegate.h"
#include "base/time/time.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/views/paint_info.h"
namespace ash {
GradientLayerDelegate::GradientLayerDelegate(bool animate_in)
: layer_(ui::LAYER_TEXTURED) {
layer_.set_delegate(this);
layer_.SetFillsBoundsOpaquely(false);
if (animate_in) {
animation_ = std::make_unique<gfx::LinearAnimation>(
base::Milliseconds(50), gfx::LinearAnimation::kDefaultFrameRate,
/*delegate=*/this);
animation_->Start();
// The animation is usually 2 or 3 frames. Instead of starting the animation
// at 0.0, which results in a fully transparent frame in the beginning, use
// an initial value so the first frame is partially opaque.
animation_->SetCurrentValue(0.333);
}
}
GradientLayerDelegate::~GradientLayerDelegate() {
layer_.set_delegate(nullptr);
}
void GradientLayerDelegate::OnPaintLayer(const ui::PaintContext& context) {
const gfx::Size size = layer()->size();
views::PaintInfo paint_info =
views::PaintInfo::CreateRootPaintInfo(context, size);
const auto& paint_recording_size = paint_info.paint_recording_size();
// Pass the scale factor when constructing PaintRecorder so the MaskLayer
// size is not incorrectly rounded (see https://crbug.com/921274).
ui::PaintRecorder recorder(
context, paint_info.paint_recording_size(),
static_cast<float>(paint_recording_size.width()) / size.width(),
static_cast<float>(paint_recording_size.height()) / size.height(),
nullptr);
recorder.canvas()->DrawColor(SK_ColorBLACK, SkBlendMode::kSrc);
if (!start_fade_zone_.zone_rect.IsEmpty())
DrawFadeZone(start_fade_zone_, recorder.canvas());
if (!end_fade_zone_.zone_rect.IsEmpty())
DrawFadeZone(end_fade_zone_, recorder.canvas());
}
void GradientLayerDelegate::AnimationProgressed(
const gfx::Animation* animation) {
DCHECK_EQ(animation, animation_.get());
// Schedule repaint of the affected areas.
if (!start_fade_zone_.zone_rect.IsEmpty())
layer_.SchedulePaint(start_fade_zone_.zone_rect);
if (!end_fade_zone_.zone_rect.IsEmpty())
layer_.SchedulePaint(end_fade_zone_.zone_rect);
}
void GradientLayerDelegate::DrawFadeZone(const FadeZone& fade_zone,
gfx::Canvas* canvas) {
gfx::Point start_point;
gfx::Point end_point;
if (fade_zone.is_horizontal) {
start_point = gfx::Point(fade_zone.zone_rect.x(), 0);
end_point = gfx::Point(fade_zone.zone_rect.right(), 0);
} else {
start_point = gfx::Point(0, fade_zone.zone_rect.y());
end_point = gfx::Point(0, fade_zone.zone_rect.bottom());
}
cc::PaintFlags flags;
flags.setBlendMode(SkBlendMode::kSrc);
flags.setAntiAlias(false);
SkColor target_color;
if (animation_) {
// Animation runs 0.0 to 1.0, so alpha runs 255 (opaque) to 0 (transparent).
uint8_t alpha = (1.0 - animation_->GetCurrentValue()) * 255;
target_color = SkColorSetA(SK_ColorTRANSPARENT, alpha);
} else {
target_color = SK_ColorTRANSPARENT;
}
flags.setShader(gfx::CreateGradientShader(
start_point, end_point, fade_zone.fade_in ? target_color : SK_ColorBLACK,
fade_zone.fade_in ? SK_ColorBLACK : target_color));
canvas->DrawRect(fade_zone.zone_rect, flags);
}
} // namespace ash