blob: 9c9bc255fec0a4b8e68e79b6104b2309db499274 [file] [log] [blame]
// Copyright 2017 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 "components/viz/common/frame_sinks/copy_output_util.h"
#include <stdint.h>
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
namespace viz {
namespace copy_output {
namespace {
// Returns the same values as std::ceil(t * numerator / denominator), but
// without introducing floating-point math and using 64-bit integer ops to avoid
// overflow.
int64_t CeilScale(int32_t t, int32_t numerator, int32_t denominator) {
int64_t x = static_cast<int64_t>(t) * numerator;
if (x > 0)
x += denominator - 1;
return x / denominator;
}
// Returns the same values as std::floor(t * numerator / denominator), but
// without introducing floating-point math and using 64-bit integer ops to avoid
// overflow.
int64_t FloorScale(int32_t t, int32_t numerator, int32_t denominator) {
if (t < 0)
return -CeilScale(-t, numerator, denominator);
return (static_cast<int64_t>(t) * numerator) / denominator;
}
} // namespace
gfx::Rect ComputeResultRect(const gfx::Rect& area,
const gfx::Vector2d& scale_from,
const gfx::Vector2d& scale_to) {
DCHECK_GT(scale_from.x(), 0);
DCHECK_GT(scale_from.y(), 0);
DCHECK_GT(scale_to.x(), 0);
DCHECK_GT(scale_to.y(), 0);
const int64_t x = FloorScale(area.x(), scale_to.x(), scale_from.x());
const int64_t y = FloorScale(area.y(), scale_to.y(), scale_from.y());
const int64_t w =
area.width() == 0
? 0
: (CeilScale(area.right(), scale_to.x(), scale_from.x()) - x);
const int64_t h =
area.height() == 0
? 0
: (CeilScale(area.bottom(), scale_to.y(), scale_from.y()) - y);
// These constants define the "reasonable" range of result Rect coordinates.
constexpr int kMaxOriginOffset = (1 << 24) - 1; // Arbitrary, but practical.
constexpr int kMaxDimension = (1 << 15) - 1; // From media/base/limits.h.
// If the result Rect is not "safely reasonable," return an empty Rect instead
// to indicate to the client that scaling should not be attempted.
if (x < -kMaxOriginOffset || x > kMaxOriginOffset || y < -kMaxOriginOffset ||
y > kMaxOriginOffset || w <= 0 || w > kMaxDimension || h <= 0 ||
h > kMaxDimension) {
return gfx::Rect();
}
return gfx::Rect(static_cast<int>(x), static_cast<int>(y),
static_cast<int>(w), static_cast<int>(h));
}
} // namespace copy_output
} // namespace viz