blob: 73c0ccf6e3e32abb04882e57782fc4eb3784f046 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/resize_utils.h"
#include "base/check_op.h"
#include "base/cxx17_backports.h"
#include "base/numerics/safe_conversions.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace gfx {
namespace {
// This function decides whether SizeRectToAspectRatio() will adjust the height
// to match the specified width (resizing horizontally) or vice versa (resizing
// vertically).
bool IsResizingHorizontally(ResizeEdge resize_edge) {
switch (resize_edge) {
case ResizeEdge::kLeft:
case ResizeEdge::kRight:
case ResizeEdge::kTopLeft:
case ResizeEdge::kBottomLeft:
return true;
default:
return false;
}
}
} // namespace
void SizeRectToAspectRatio(ResizeEdge resize_edge,
float aspect_ratio,
const Size& min_window_size,
const Size& max_window_size,
Rect* rect) {
DCHECK_GT(aspect_ratio, 0.0f);
DCHECK_GE(max_window_size.width(), min_window_size.width());
DCHECK_GE(max_window_size.height(), min_window_size.height());
DCHECK(rect->Contains(Rect(rect->origin(), min_window_size)))
<< rect->ToString() << " is smaller than the minimum size "
<< min_window_size.ToString();
DCHECK(Rect(rect->origin(), max_window_size).Contains(*rect))
<< rect->ToString() << " is larger than the maximum size "
<< max_window_size.ToString();
Size new_size = rect->size();
if (IsResizingHorizontally(resize_edge)) {
new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
if (min_window_size.height() > new_size.height() ||
new_size.height() > max_window_size.height()) {
new_size.set_height(base::clamp(new_size.height(),
min_window_size.height(),
max_window_size.height()));
new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
}
} else {
new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
if (min_window_size.width() > new_size.width() ||
new_size.width() > max_window_size.width()) {
new_size.set_width(base::clamp(new_size.width(), min_window_size.width(),
max_window_size.width()));
new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
}
}
// The dimensions might still be outside of the allowed ranges at this point.
// This happens when the aspect ratio makes it impossible to fit |rect|
// within the size limits without letter-/pillarboxing.
new_size.SetToMin(max_window_size);
new_size.SetToMax(min_window_size);
// |rect| bounds before sizing to aspect ratio.
int left = rect->x();
int top = rect->y();
int right = rect->right();
int bottom = rect->bottom();
switch (resize_edge) {
case ResizeEdge::kRight:
case ResizeEdge::kBottom:
right = new_size.width() + left;
bottom = top + new_size.height();
break;
case ResizeEdge::kTop:
right = new_size.width() + left;
top = bottom - new_size.height();
break;
case ResizeEdge::kLeft:
case ResizeEdge::kTopLeft:
left = right - new_size.width();
top = bottom - new_size.height();
break;
case ResizeEdge::kTopRight:
right = left + new_size.width();
top = bottom - new_size.height();
break;
case ResizeEdge::kBottomLeft:
left = right - new_size.width();
bottom = top + new_size.height();
break;
case ResizeEdge::kBottomRight:
right = left + new_size.width();
bottom = top + new_size.height();
break;
}
rect->SetByBounds(left, top, right, bottom);
}
} // namespace gfx