mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
fix: crop the documentation frames on whole pixels
Замер снял главное: три снимка подряд в одном состоянии страницы совпадают побайтово у всех десяти сценариев. Значит рендер детерминирован, а плавает то, что приходит на вход съёмке. Обрезка считается из живого DOM через getBoundingClientRect и приходит дробной. Дробная обрезка заставляет Chromium ресемплить кадр — и тогда сдвиг раскладки на десятую пикселя переписывает границы всех элементов на единицы уровней. Ровно эта подпись в #410: 76 пикселей, максимум 2 уровня, alpha не тронута, всё на сглаженных границах полей. Рамка расширяется наружу, а не округляется к ближайшему: обрезка обязана содержать цель целиком. Issue: #410 User-Visible: no
This commit is contained in:
+27
-1
@@ -262,9 +262,35 @@ try {
|
||||
const runtime = await applyDocumentationState(page, scenario);
|
||||
if (scenario.expectDialog && !runtime.dialog)
|
||||
throw new Error(`documentation scenario did not open its dialog: ${scenario.id}`);
|
||||
const clip = scenario.capture === 'room-card'
|
||||
const rawClip = scenario.capture === 'room-card'
|
||||
? await roomCardClip(page)
|
||||
: await goldenClip(page, scenario.capture);
|
||||
// Обрезка выравнивается по целым пикселям (#410).
|
||||
//
|
||||
// Прямоугольник считается из живого DOM через getBoundingClientRect, то есть
|
||||
// приходит дробным. Дробная обрезка заставляет Chromium ресемплить кадр, и
|
||||
// тогда сдвиг раскладки на десятую пикселя — от метрики шрифта, от
|
||||
// появившегося скроллбара — переписывает границы всех элементов на единицы
|
||||
// уровней. Ровно эта подпись и была в #410: 76 пикселей, максимум 2 уровня,
|
||||
// alpha не тронута, всё на сглаженных границах полей.
|
||||
//
|
||||
// Замер показал, где искать: три снимка подряд в одном состоянии страницы
|
||||
// совпадают побайтово у всех десяти сценариев, а между прогонами плавают
|
||||
// два. Значит дело не в рендере, а в том, что приходит на вход съёмке.
|
||||
//
|
||||
// Внешняя рамка расширяется, а не округляется к ближайшему: обрезка обязана
|
||||
// содержать цель целиком, потерять полпикселя по краю нельзя.
|
||||
const clip = rawClip && {
|
||||
x: Math.floor(rawClip.x),
|
||||
y: Math.floor(rawClip.y),
|
||||
width: Math.ceil(rawClip.x + rawClip.width) - Math.floor(rawClip.x),
|
||||
height: Math.ceil(rawClip.y + rawClip.height) - Math.floor(rawClip.y),
|
||||
};
|
||||
if (STABILITY_SHOTS && rawClip) {
|
||||
console.log(`${scenario.id} обрезка: сырая`
|
||||
+ ` ${rawClip.x},${rawClip.y} ${rawClip.width}x${rawClip.height}`
|
||||
+ ` → целая ${clip.x},${clip.y} ${clip.width}x${clip.height}`);
|
||||
}
|
||||
// Два кадра ожидания перед съёмкой — как в golden. `animations: 'disabled'`
|
||||
// гасит анимации, но не гарантирует, что уже запланированный ре-рендер
|
||||
// успел лечь в композитор до захвата.
|
||||
|
||||
Reference in New Issue
Block a user