// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia_web/webengine/browser/frame_layout_manager.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/transform.h"
namespace {
// Returns a scaling factor that will allow |inset| to fit fully inside
// |container| without clipping.
float ProportionalScale(gfx::Size inset, gfx::Size container) {
gfx::SizeF inset_f(inset);
gfx::SizeF container_f(container);
const float container_aspect_ratio =
container_f.width() / container_f.height();
const float inset_aspect_ratio = inset_f.width() / inset_f.height();
if (container_aspect_ratio > inset_aspect_ratio) {
// Height is constraining.
return container_f.height() / inset_f.height();
} else {
// Width is constraining.
return container_f.width() / inset_f.width();
}
}
} // namespace
FrameLayoutManager::FrameLayoutManager() = default;
FrameLayoutManager::~FrameLayoutManager() = default;
void FrameLayoutManager::ForceContentDimensions(gfx::Size size) {
render_size_override_ = size;
UpdateContentBounds();
}
void FrameLayoutManager::OnWindowResized() {
// Resize the child to match the size of the parent.
UpdateContentBounds();
}
void FrameLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
if (child->GetType() == aura::client::WINDOW_TYPE_CONTROL) {
DCHECK(!main_child_);
main_child_ = child;
SetChildBoundsDirect(main_child_,
gfx::Rect(main_child_->parent()->bounds().size()));
UpdateContentBounds();
// Make the compositor's background transparent by default.
main_child_->parent()->GetHost()->compositor()->SetBackgroundColor(
SK_AlphaTRANSPARENT);
main_child_->GetHost()->compositor()->SetBackgroundColor(
SK_AlphaTRANSPARENT);
}
}
void FrameLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
if (child->GetType() == aura::client::WINDOW_TYPE_CONTROL) {
DCHECK_EQ(child, main_child_);
main_child_ = nullptr;
}
}
void FrameLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {}
void FrameLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) {}
void FrameLayoutManager::SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) {
if (child != main_child_)
SetChildBoundsDirect(child, requested_bounds);
}
void FrameLayoutManager::UpdateContentBounds() {
if (!main_child_)
return;
const gfx::Size actual_size(main_child_->parent()->bounds().size());
if (render_size_override_.IsEmpty()) {
// Use all of the area available to the View.
SetChildBoundsDirect(main_child_, gfx::Rect(actual_size));
main_child_->SetTransform(gfx::Transform());
return;
}
SetChildBoundsDirect(main_child_, gfx::Rect(render_size_override_));
// Scale the window to fit in the View without clipping.
const float scale = ProportionalScale(render_size_override_, actual_size);
gfx::Transform transform;
transform.Scale(scale, scale);
// Center the window.
const float center_x_offset =
(actual_size.width() - (render_size_override_.width() * scale)) / 2.0;
const float center_y_offset =
(actual_size.height() - (render_size_override_.height() * scale)) / 2.0;
transform.Translate(center_x_offset, center_y_offset);
main_child_->SetTransform(transform);
}