chromium/components/javascript_dialogs/views/layer_dimmer.cc

// 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 "components/javascript_dialogs/views/layer_dimmer.h"

#include <memory>

#include "base/time/time.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_layer_animation_settings.h"

namespace javascript_dialogs {

LayerDimmer::LayerDimmer(aura::Window* parent, aura::Window* dialog)
    : parent_(parent), dialog_(dialog) {
  auto* parentLayer = parent_->layer();

  layer_ = std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR);
  layer_->SetName(parent_->GetName() + "_LayerDimmer");
  layer_->SetAnimator(new ui::LayerAnimator(base::Milliseconds(200)));
  layer_->SetColor(SkColorSetA(SK_ColorBLACK, 127));
  {
    // Don't animate these changes right now.
    ui::ScopedLayerAnimationSettings settings(layer_->GetAnimator());
    settings.SetTransitionDuration(base::Milliseconds(0));
    layer_->SetOpacity(0.f);
    layer_->SetBounds(parent_->bounds());
  }

  parentLayer->Add(layer_.get());
  StackLayerUnderDialog();

  parent_->AddObserver(this);
  dialog_->AddObserver(this);
}

LayerDimmer::~LayerDimmer() {
  if (parent_) {
    parent_->RemoveObserver(this);
  }
  if (dialog_) {
    dialog_->RemoveObserver(this);
  }
}

void LayerDimmer::Show() {
  layer_->SetOpacity(1.0f);
  layer_->ScheduleDraw();
}

void LayerDimmer::Hide() {
  layer_->SetOpacity(0.f);
  layer_->ScheduleDraw();
}

void LayerDimmer::StackLayerUnderDialog() {
  auto* parentLayer = parent_->layer();
  parentLayer->StackBelow(layer_.get(), dialog_->layer());
  layer_->ScheduleDraw();
}

void LayerDimmer::OnWindowBoundsChanged(aura::Window* window,
                                        const gfx::Rect& old_bounds,
                                        const gfx::Rect& new_bounds,
                                        ui::PropertyChangeReason reason) {
  if (window == parent_) {
    // Don't animate this bounds change.
    ui::ScopedLayerAnimationSettings settings(layer_->GetAnimator());
    settings.SetTransitionDuration(base::Milliseconds(0));
    layer_->SetBounds(gfx::Rect(new_bounds.size()));
  }
}

void LayerDimmer::OnWindowDestroying(aura::Window* window) {
  if (window == parent_) {
    parent_->RemoveObserver(this);
    parent_ = nullptr;
  } else {
    DCHECK_EQ(dialog_, window);
    dialog_->RemoveObserver(this);
    dialog_ = nullptr;
  }
}

void LayerDimmer::OnWindowStackingChanged(aura::Window* window) {
  if (window == dialog_) {
    StackLayerUnderDialog();
  }
}

}  // namespace javascript_dialogs