diff options
| author | omar <69222225+arrowpc@users.noreply.github.com> | 2025-09-28 04:14:43 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-27 20:14:43 +0200 |
| commit | ef479ff5392682c3b92d133dee1f7f937f52072b (patch) | |
| tree | e7c4bb24ce647d8c3a1cb666e701a89cbde69ca1 /src/protocols/Viewporter.cpp | |
| parent | 6f1d2e771dca1b5eea5ec344ca1b6a80d4fd4ee5 (diff) | |
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.
Diffstat (limited to 'src/protocols/Viewporter.cpp')
| -rw-r--r-- | src/protocols/Viewporter.cpp | 27 |
1 files 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 <algorithm> +#include <cmath> CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_) : m_surface(surface_), m_resource(resource_) { if UNLIKELY (!good()) @@ -60,9 +61,31 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes return; 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_surface->m_pending.rejected = true; return; |
