summaryrefslogtreecommitdiff
path: root/src/protocols/Viewporter.cpp
diff options
context:
space:
mode:
authoromar <69222225+arrowpc@users.noreply.github.com>2025-09-28 04:14:43 +1000
committerGitHub <noreply@github.com>2025-09-27 20:14:43 +0200
commitef479ff5392682c3b92d133dee1f7f937f52072b (patch)
treee7c4bb24ce647d8c3a1cb666e701a89cbde69ca1 /src/protocols/Viewporter.cpp
parent6f1d2e771dca1b5eea5ec344ca1b6a80d4fd4ee5 (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.cpp27
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;