/** * Выравнивание области съёмки по целым пикселям (#410, гейт — #422). * * Прямоугольник приходит из живого DOM через `getBoundingClientRect`, то есть * дробным. Дробная обрезка заставляет Chromium ресемплить кадр, и тогда сдвиг * раскладки на десятую пикселя — от метрики шрифта, от появившегося * скроллбара — переписывает границы всех элементов на единицы уровней. Ровно * эта подпись и была в #410: 76 пикселей, максимум 2 уровня, alpha не тронута, * всё на сглаженных границах полей. * * Внешняя рамка РАСШИРЯЕТСЯ, а не округляется к ближайшему: обрезка обязана * содержать цель целиком, потерять полпикселя по краю нельзя. Именно поэтому * здесь `floor` для начала и `ceil` для конца, а не `Math.round` — округление к * ближайшему срезало бы край на половине входов. * * Функция живёт отдельным модулем, потому что она чистая, а `capture.mjs` — * исполняемый скрипт: импортировать его в тест значит запустить съёмку. */ export function wholePixelClip(rect) { if (!rect) return rect; const x = Math.floor(rect.x); const y = Math.floor(rect.y); return { x, y, width: Math.ceil(rect.x + rect.width) - x, height: Math.ceil(rect.y + rect.height) - y, }; }