From ef479ff5392682c3b92d133dee1f7f937f52072b Mon Sep 17 00:00:00 2001 From: omar <69222225+arrowpc@users.noreply.github.com> Date: Sun, 28 Sep 2025 04:14:43 +1000 Subject: [PATCH] viewporter: clamp sub-pixel overflow (#11845) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/protocols/Viewporter.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 06a47382..9612d3f8 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -1,6 +1,7 @@ #include "Viewporter.hpp" #include "core/Compositor.hpp" #include +#include CViewportResource::CViewportResource(SP resource_, SP surface_) : m_surface(surface_), m_resource(resource_) { if UNLIKELY (!good()) @@ -60,9 +61,31 @@ CViewportResource::CViewportResource(SP resource_, SPm_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_surface->m_pending.rejected = true; return;