viewporter: clamp sub-pixel overflow (#11845)
Clamps the pending wp_viewport source rect back inside the attached buffer when it misses by <= 1 px, so if clients request something that falls within the 256-increment wl_fixed_from_double precision error it’s still treated as valid.
This commit is contained in:
parent
6f1d2e771d
commit
ef479ff539
1 changed files with 25 additions and 2 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
#include "Viewporter.hpp"
|
#include "Viewporter.hpp"
|
||||||
#include "core/Compositor.hpp"
|
#include "core/Compositor.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_) : m_surface(surface_), m_resource(resource_) {
|
CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_) : m_surface(surface_), m_resource(resource_) {
|
||||||
if UNLIKELY (!good())
|
if UNLIKELY (!good())
|
||||||
|
|
@ -60,9 +61,31 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_surface->m_pending.viewport.hasSource) {
|
if (m_surface->m_pending.viewport.hasSource) {
|
||||||
auto& src = m_surface->m_pending.viewport.source;
|
auto& src = m_surface->m_pending.viewport.source;
|
||||||
|
const auto& size = m_surface->m_pending.bufferSize;
|
||||||
|
|
||||||
if (src.w + src.x > m_surface->m_pending.bufferSize.x || src.h + src.y > m_surface->m_pending.bufferSize.y) {
|
if (size.x <= 0.0 || size.y <= 0.0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
constexpr wl_fixed_t MAX_TOLERANCE = 1 << 8; // wl_fixed 1.0 = 256
|
||||||
|
|
||||||
|
auto clampAxis = [&](double& start, double& length, double limit) -> bool {
|
||||||
|
const double originalStart = start;
|
||||||
|
const double originalEnd = start + length;
|
||||||
|
const double clampedStart = std::clamp(start, 0.0, std::max(0.0, limit));
|
||||||
|
const double clampedEnd = std::clamp(originalEnd, 0.0, std::max(0.0, limit));
|
||||||
|
const wl_fixed_t startDelta = std::abs(wl_fixed_from_double(clampedStart) - wl_fixed_from_double(originalStart));
|
||||||
|
const wl_fixed_t endDelta = std::abs(wl_fixed_from_double(clampedEnd) - wl_fixed_from_double(originalEnd));
|
||||||
|
|
||||||
|
if (startDelta > MAX_TOLERANCE || endDelta > MAX_TOLERANCE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
start = clampedStart;
|
||||||
|
length = clampedEnd - clampedStart;
|
||||||
|
return length > 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!clampAxis(src.x, src.w, size.x) || !clampAxis(src.y, src.h, size.y)) {
|
||||||
m_resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
m_resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
||||||
m_surface->m_pending.rejected = true;
|
m_surface->m_pending.rejected = true;
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue