Skip to content

Latest commit

 

History

History
1055 lines (725 loc) · 28.8 KB

File metadata and controls

1055 lines (725 loc) · 28.8 KB

Контракт RectsPatchModule

0. Назначение документа

Документ фиксирует текущий контракт работы модуля:

RectsPatchModule является window-realm модулем влияния на DOM/SVG layout и rendering inputs, которые затем измеряются нативным Chromium через DOMRect, DOMRectList, Element.getBoundingClientRect(), Element.getClientRects(), Range.getBoundingClientRect(), Range.getClientRects() и SVG layout/geometry APIs.

Модуль не является patch-модулем public Web IDL methods/accessors. Его задача - не заменить rect API, а подготовить controlled layout/rendering influence так, чтобы Chromium сам посчитал geometry через штатный native path.

Главная формула контракта:

seed/profile/state -> CSS/layout influence -> native Chromium layout -> native rect measurements

Модуль не должен превращаться в compatibility binding под один внешний стенд. Имена внутренних каналов описывают тип измеряемого источника layout/rendering, а не имена элементов конкретной страницы.


1. Нормативная рамка

Приоритеты:

  1. Внешний нормативный контракт ECMAScript, Web IDL, MDN, Chromium runtime fact.
  2. Policy_implement_reg.md: object/function/proxy/property/apply path.
  3. Hidden_State_FernwehContext_Contract.md: owner-state и hidden slots.
  4. DEGRADE_Contract.md: observed diagnostics и запрет silent-swallow.
  5. Текущая прикладная логика RectsPatchModule.

Ключевое следствие:

RectsPatchModule не имеет права ломать descriptor/receiver/apply/toString/proxy invariants public API.

Для rect surfaces нормативный внешний слой остаётся у Chromium:

  • Web IDL methods остаются native built-in function objects;
  • descriptors остаются на своих Chromium owners;
  • bad receiver path остаётся native;
  • Function.prototype.toString остаётся engine baseline;
  • Proxy exotic wrapper не должен появляться на public rect method surface;
  • DOMRect / DOMRectReadOnly object shape не подменяется модулем.

2. Scope модуля

Модуль работает только в window realm.

Entrypoint:

RectsPatchModule(window);

Файл подключается в main.py в bundle window-патчей и вызывается после bootstrap/core/screen/nav setup и до downstream graphics/media modules.

Текущий pipeline-order:

BootstrapHideModule(window)
set_log.js
prng_seed.js
core_window.js
...
ScreenPatchModule(window)
RectsPatchModule(window)
FontPatchModule(window)
CanvasPatchModule(window)
...

RectsPatchModule ожидает, что bootstrap owner-space уже создан:

window.FernwehContext
window.FernwehContext.state
window.Core
Core.__internal.prng
Core.guardFlag
Core.releaseGuardFlag
FernwehContext.__logger.__DEGRADE__

Если обязательная структура отсутствует, это pipeline missing data и fail-fast, а не soft-skip.


3. Что модуль делает

Модуль делает четыре вещи:

  1. Проверяет наличие обязательного owner-state и profile/state inputs.
  2. Строит детерминированный набор CSS/layout influence values из seed, screen metrics и fonts profile.
  3. Находит в текущем document измерительные fixture-candidates через широкие каналы layout/rendering, без id/class binding конкретного стенда.
  4. Применяет inline style influence к найденным candidates и повторяет scan через MutationObserver, queueMicrotask и setTimeout.

Модуль влияет на измерения DOM/CSS inputs перед нативным layout calculation.


4. Модуль не должен:

  • патчить Element.prototype.getBoundingClientRect;
  • патчить Element.prototype.getClientRects;
  • патчить Range.prototype.getBoundingClientRect;
  • патчить Range.prototype.getClientRects;
  • патчить DOMRect, DOMRectReadOnly, DOMRectList;
  • создавать callable Proxy вокруг rect methods;
  • создавать JS-wrapper для native rect methods;
  • менять descriptor shape public Web IDL operations;
  • менять Function.prototype.toString;
  • добавлять detector-specific selector binding в module logic;
  • искать конкретные id / class вроде measurement names отдельного стенда;
  • использовать querySelector, getElementById, getElementsByClassName как binding path для rect influence;
  • создавать stylesheet с hardcoded page selectors под конкретный стенд;
  • писать public service globals на window;
  • использовать Math.random;
  • использовать fallback values при отсутствии обязательного state.

5. Hidden owner-state

Canonical owner-state модуля:

FernwehContext.state.__RECTS__
  __STATE__
  __CONFIG__

bootstrap_hide.js является owner создания hidden slots:

FernwehContext.state.__RECTS__.__STATE__
FernwehContext.state.__RECTS__.__CONFIG__

RectsPatchModule является consumer и runtime owner значений внутри своего module slot. Он не создаёт root FernwehContext, не создаёт C.state и не пересоздаёт чужие module slots.

5.1. __STATE__

Текущая форма:

FernwehContext.state.__RECTS__.__STATE__ = {
  ready: boolean,
  status: string,
  reason: string | null,
  error: string | null,
  applied: number,
  targets: number
}

Смысл полей:

Поле Назначение
ready модуль завершил apply path без fatal error
status bootstrap, applying, ready, error
reason текущая причина состояния, для успешного path: layout_influence
error текст ошибки при failure path или null
applied количество style-property assignments, применённых модулем
targets количество найденных measurement candidates по каналам

ready: true означает, что observer установлен и apply path завершён. Это не означает, что на странице обязательно были найдены measurement candidates в момент первого scan.

5.2. __CONFIG__

Текущая форма:

FernwehContext.state.__RECTS__.__CONFIG__ = {
  maxMeasurementScan: number
}

maxMeasurementScan задаёт верхний предел сканирования ordinary DOM elements через document.getElementsByTagName('*').

Default создаётся в bootstrap_hide.js:

2048

Это не detector binding. Это safety bound для DOM scan, чтобы эвристика не превращалась в безлимитный обход страницы.

Если maxMeasurementScan отсутствует, не число или <= 0, RectsPatchModule обязан завершиться fail-fast:

rects:measurement_scan_limit_invalid

6. Source-of-truth inputs

Модуль берёт значения только из существующих owner-paths.

6.1. Seed / PRNG

Canonical PRNG owner:

Core.__internal.prng
  seed
  strToSeed
  mulberry32

RectsPatchModule не читает window.__GLOBAL_SEED как consumer-path.

Seed derivation строится через:

__unit(label)

Формула:

rects-layout | label | Core.__internal.prng.seed

Допустимые seed labels текущего модуля:

html-layout-geometry-width
text-glyph-metrics-font-size
text-glyph-metrics-letter-spacing
font-family

Эти labels не являются именами DOM-целей. Это labels deterministic branches внутри rect layout influence.

6.2. Screen metrics

Canonical source:

FernwehContext.state.__SCREEN__
  width
  height
  dpr

width, height, dpr должны быть finite positive numbers. Для текущего rect influence непосредственно используется dpr, но preflight проверяет весь базовый screen metrics set, потому что это единый screen owner-state модуля.

6.3. Fonts profile

Canonical source:

FernwehContext.state.__FONTS__.__CONFIG__.configs

Модуль выбирает CSS family из fonts config. Если доступен FernwehContext.state.__ENV_PROFILE__.__PLATFORM__.domPlatform и font configs имеют platform_dom, список сужается до соответствующей platform group.

Допустимые поля font config для имени family:

cssFamily
family
full_name
postscript_name

Выбор family детерминирован seed branch font-family.

Если font config отсутствует или после нормализации не остаётся ни одного имени, это fail-fast:

rects:fonts_config_missing
rects:font_family_missing

7. Layout influence values

Текущий influence строится в __buildLayoutInfluence(fontFamily).

Выход:

{
  fontFamily,
  htmlLayoutGeometryWidth,
  textGlyphMetricsFontSize,
  textGlyphMetricsLetterSpacing
}

7.1. fontFamily

CSS string quoted через __quoteCssString.

Назначение: влиять на text glyph metrics через штатный CSS font selection path.

7.2. htmlLayoutGeometryWidth

Форма:

calc(1000.099% + <delta>px)

delta детерминирован через seed и dpr.

Назначение: влиять на HTML layout geometry контейнера, который участвует в measurement.

7.3. textGlyphMetricsFontSize

Форма:

calc(200px + <delta>px)

delta детерминирован через seed и dpr.

Назначение: влиять на glyph metric calculation без подмены rect API.

7.4. textGlyphMetricsLetterSpacing

Форма:

<delta>px

delta детерминирован через seed и dpr.

Назначение: влиять на spacing component text layout.

7.5. svgLayoutGeometry

Текущее правило:

overflow: visible

Назначение: не скрывать SVG geometry при native SVG layout measurement.


8. Каналы измерения

Модуль использует четыре внутренние rule-группы. Это не нормативные имена Web IDL сущностей, а честные проектные labels фактических layout/rendering channels.

8.1. htmlLayoutGeometry

Канал HTML layout geometry.

Сущность: видимый HTML container/ancestor/offsetParent, который влияет на native rect calculation дочернего measurement node

Применяемые rules:

width

Источник candidates:

  • ближайший parent/ancestor с visible layout rect;
  • offsetParent, если он имеет visible layout rect;
  • parent fallback, если он имеет visible layout rect.

8.2. textGlyphMetrics

Канал text glyph metrics.

Сущность: deepest visible element, whose textContent contains emoji/symbol glyphs

Применяемые rules:

font-family
font-size
letter-spacing

Источник candidates:

  • elements from bounded scan;
  • textContent содержит glyph по __glyphTextPattern;
  • элемент является deepest glyph element;
  • элемент имеет visible layout rect.

8.3. pixelGlyphRendering

Канал pixel/glyph rendering.

Сущность: тот же видимый glyph element, рассматриваемый как rendering metric source

Применяемые rules:

font-family
font-size
letter-spacing

Этот канал фиксирует, что текстовый glyph node может участвовать в pixel/rendering side measurements.

8.4. svgLayoutGeometry

Канал SVG layout geometry.

Сущность: visible SVG node, measured by native SVG/layout geometry APIs

Применяемые rules:

overflow

Источник candidates:

document.getElementsByTagName('svg')

SVG scan не ограничивается maxMeasurementScan, потому что SVG nodes сканируются отдельным tag route.


9. Discovery contract

Discovery function:

__collectMeasurementFixtureCandidates()

Обязательное browser capability:

document.getElementsByTagName

Если capability отсутствует:

rects:get_elements_by_tag_name_missing

9.1. SVG scan

Порядок:

  1. Получить document.getElementsByTagName('svg').
  2. Для каждого SVG node проверить visible layout rect.
  3. Добавить SVG node в svgLayoutGeometry.
  4. Добавить ближайший layout container в htmlLayoutGeometry.

Счётчики:

svgScanned
scanned

9.2. Element scan

Порядок:

  1. Получить document.getElementsByTagName('*').
  2. Идти по DOM order до maxMeasurementScan.
  3. Проверить deepest glyph element.
  4. Проверить visible layout rect.
  5. Добавить element в textGlyphMetrics.
  6. Добавить element в pixelGlyphRendering.
  7. Добавить nearest layout container в htmlLayoutGeometry.

Счётчики:

elementScanned
scanned

9.3. Visible layout rect

Проверка:

el.getClientRects()

Условие:

есть rect с width > 0 и height > 0

Это чтение нативного метода, а не patch этого метода. Оно используется только как discovery predicate.

Если чтение rects у candidate throws, модуль не должен silent-swallow. Он один раз эмитит:

rects:measurement_candidate_rect_read_failed

После этого конкретный candidate считается непригодным.

9.4. Glyph predicate

Текущий glyph predicate:

/[\u00A9\u00AE\u203C-\u3299]|[\uD83C-\uDBFF][\uDC00-\uDFFF]/

Назначение: широкий detection emoji/symbol glyph text, а не selector binding.

Ограничение: это эвристика. Она может поймать реальные видимые glyph nodes страницы. Это допустимый текущий риск layout influence модели, но не основание возвращаться к hardcoded detector selectors.


10. Apply contract

Apply function:

__applyLayoutInfluence(styles)

Применение идёт только через inline style API:

el.style.setProperty(key, value, '')

Priority всегда пустой:

без !important

Перед записью проверяется текущее значение:

style.getPropertyValue(key)
style.getPropertyPriority(key)

Если property уже имеет нужное значение и пустой priority, повторная запись не считается applied.

10.1. Схема применения

htmlLayoutGeometry candidates -> styles.htmlLayoutGeometry
textGlyphMetrics candidates -> styles.textGlyphMetrics
pixelGlyphRendering candidates -> styles.textGlyphMetrics
svgLayoutGeometry candidates -> styles.svgLayoutGeometry

Модуль не создаёт stylesheet node и не строит selector CSS. Это важно: текущая модель не привязана к именам DOM элементов.

10.2. State updates

После scan:

__rectsState.targets = measurementTargetCount;

Если были реальные style assignments:

__rectsState.applied += applied;

Если candidates найдены впервые, эмитится telemetry:

rects:measurement_fixtures_discovered

Data shape:

{
  outcome: 'return',
  candidates: {
    htmlLayoutGeometry,
    textGlyphMetrics,
    pixelGlyphRendering,
    svgLayoutGeometry
  },
  channels,
  scanned,
  svgScanned,
  elementScanned,
  measurementTargetCount,
  applied
}

11. Runtime observer lifecycle

Observer installation:

__installLayoutObserver()

Обязательное browser capability:

window.MutationObserver

Если отсутствует:

rects:mutation_observer_missing

Порядок:

  1. Выполнить initial scan/apply.
  2. Создать new window.MutationObserver(...).
  3. Observe target:
document.documentElement || document

Options:

{ childList: true, subtree: true }
  1. Запланировать дополнительный scan через queueMicrotask, если capability существует.
  2. Запланировать дополнительный scan через setTimeout(..., 0), если capability существует.

Если observer callback throws при apply:

rects:layout_influence_apply_failed

Ошибка пробрасывается дальше. Это не soft-fail.

Если scheduling throws:

rects:layout_influence_schedule_failed

Ошибка пробрасывается дальше.


12. Guard lifecycle

Guard key:

__PATCH_RECTS__

Guard owner:

Core.__internal.guards
Core.guardFlag
Core.releaseGuardFlag

Модуль берёт guard до preflight и write side effects.

Если Core.guardFlag отсутствует:

rects:guard_missing

Если Core.guardFlag throws:

rects:guard_failed

Если guard acquisition возвращает falsy token, модуль возвращает 0 и не выполняет apply.

Текущая реализация снимает guard после successful observer installation через:

__releaseGuard(true)

Это означает, что guard в данном модуле используется как apply-entry lifecycle guard, а не как permanent patched-target lock. Такая форма допустима только потому, что модуль не заменяет public descriptors и не регистрирует persistent public API patch target.

При failure path:

__releaseGuard(false)

Если release throws:

rects:guard_release_failed

13. Diagnostic contract

Module id:

rects

Surface label:

DOM/SVG layout influence for native rect measurements

Adapter:

FernwehContext.__logger.__DEGRADE__.diag(level, code, ctx, err)
fallback: FernwehContext.__logger.__DEGRADE__(code, err, extra)

.diag вызывается с bound receiver:

__D.diag.bind(__D)

Logging-path failure не должен ломать модуль. Patch/apply/preflight failure при этом не становится success.

13.1. ctx shape

Модуль передаёт:

{
  module: 'rects',
  diagTag,
  surface,
  key,
  stage,
  message,
  type,
  data
}

Допустимые текущие stages:

guard
preflight
apply
runtime
rollback

13.2. Основные diag codes

Preflight / missing data:

rects:fernweh_context_state_missing
rects:document_missing
rects:screen_state_missing
rects:screen_metrics_invalid
rects:prng_missing
rects:fonts_config_missing
rects:font_family_missing
rects:state_missing
rects:measurement_scan_limit_invalid
rects:get_elements_by_tag_name_missing
rects:mutation_observer_missing

Guard:

rects:guard_missing
rects:guard_failed
rects:guard_release_failed

Runtime/apply:

rects:measurement_candidate_rect_read_failed
rects:measurement_fixtures_discovered
rects:layout_influence_apply_failed
rects:layout_influence_schedule_failed
rects:layout_influence_applied

14. State lifecycle

14.1. До apply

bootstrap_hide.js создаёт:

ready: false
status: 'bootstrap'
reason: null
error: null
applied: 0
targets: 0

14.2. Во время apply

RectsPatchModule пишет:

ready = false
status = 'applying'
reason = 'layout_influence'
error = null

14.3. При успешном apply

ready = true
status = 'ready'
error = null

reason остаётся:

layout_influence

applied и targets отражают фактическое runtime discovery/apply состояние.

14.4. При failure

ready = false
status = 'error'
reason = 'layout_influence_failed'
error = String(error)

Ошибка пробрасывается дальше после state update и guard release attempt.


15. Public API invariants

Обязательный acceptance для public rect surfaces:

Element.prototype.getBoundingClientRect
Element.prototype.getClientRects
Range.prototype.getBoundingClientRect
Range.prototype.getClientRects
DOMRect
DOMRectReadOnly

Контроль:

  • descriptors не изменены RectsPatchModule;
  • method values остаются native Chromium function objects;
  • Function.prototype.toString.call(method) возвращает Chromium native source string;
  • bad receiver path остаётся native TypeError / Illegal invocation;
  • getClientRects() возвращает native DOMRectList;
  • getBoundingClientRect() возвращает native DOMRect;
  • module diagnostics не подменяют native result/throw path;
  • отсутствует public Proxy-observability defect на rect methods.

Если для достижения layout influence требуется изменить public descriptor, это считается неверным направлением. Правильный путь - менять DOM/CSS inputs или отказаться от конкретной цели с observed diagnostic, но не ломать Web IDL method surface.


16. Hardcode policy

Запрещены detector-specific строки в logic layer:

id/class конкретного теста
CSS selectors конкретного теста
названия DOM containers конкретного теста

Разрешены:

  • стабильные project labels seed branches;
  • стабильные project labels measurement channels;
  • Web/platform generic tag name svg;
  • * для bounded generic element scan;
  • CSS property names (width, font-family, font-size, letter-spacing, overflow);
  • numeric scan bound из __RECTS__.__CONFIG__.maxMeasurementScan;
  • deterministic formulas, основанные на seed + DPR.

Разница:

htmlLayoutGeometry - это channel label.
именованный selector/page binding - это привязка к конкретной странице или стенду.

В module logic допустим первый тип, недопустим второй.


17. Current limitations

Текущая модель использует широкую эвристику по glyph/layout/SVG candidates. Поэтому на произвольной странице возможно влияние на реальные видимые элементы, если они подходят под predicate:

visible deepest emoji/symbol glyph element
visible SVG node
nearest visible layout container

Это не является silent failure: применённые targets считаются и диагностируются через __RECTS__.__STATE__ и rects:measurement_fixtures_discovered.

Если на конкретной странице будет доказан ущерб, править нужно эвристику канала или gating условий, а не возвращаться к hardcoded binding конкретного стенда.

Не доказано как универсальный факт без runtime-аудита каждой страницы:

  • что эвристика не заденет пользовательский видимый контент;
  • что bounded scan всегда успеет поймать transient measurement nodes;
  • что все внешние detectors используют measurement patterns, покрытые текущими каналами.

Эти ограничения не меняют базовый контракт: public API не патчится, influence идёт через layout/rendering inputs.


18. Управление модулем

18.1. Изменение глубины поиска

Единственный текущий конфигурационный параметр:

FernwehContext.state.__RECTS__.__CONFIG__.maxMeasurementScan

Менять его нужно через bootstrap/owner-state path, а не локальным hardcode в rects.js.

18.2. Изменение seed influence

Любое изменение величин influence должно сохранять цепочку:

Core.__internal.prng.seed
-> __unit(stable label)
-> value normalized by screen DPR / font profile
-> CSS property assignment

Нельзя вводить значения, которые появляются "ниоткуда".

18.3. Изменение каналов

Новый канал допускается только если он описывает универсальный source layout/rendering measurement, например:

CSS box metrics
font/glyph metrics
SVG geometry
pixel/rendering metrics
transform/edge geometry

Новый канал не должен быть именем внешнего теста, id/class конкретной страницы или compatibility binding.


19. Acceptance checklist

Модуль считается контрактно корректным, если:

  1. rects.js не меняет public descriptors/functions/accessors rect APIs.
  2. Element.*, Range.*, DOMRect* сохраняют native Chromium shape.
  3. Function.prototype.toString rect methods не имеет wrapper/proxy symptoms.
  4. Core.__internal.prng является единственным seed consumer-path.
  5. FernwehContext.state.__SCREEN__ является source screen metrics.
  6. FernwehContext.state.__FONTS__.__CONFIG__.configs является source font family material.
  7. FernwehContext.state.__RECTS__.__STATE__ отражает lifecycle.
  8. FernwehContext.state.__RECTS__.__CONFIG__.maxMeasurementScan управляет bounded scan.
  9. Нет hardcoded id/class/selector binding конкретного стенда.
  10. Discovery идёт через каналы htmlLayoutGeometry, textGlyphMetrics, pixelGlyphRendering, svgLayoutGeometry.
  11. Style application идёт через style.setProperty.
  12. MutationObserver используется для runtime candidates, а не для public API patching.
  13. Любой controlled failure виден через __DEGRADE__.diag.
  14. Нет silent catch {} на patch/apply/runtime failure path.
  15. Отсутствие обязательного state/capability ведёт к fail-fast, а не к soft-skip.
  16. page_bundle.js не является source of truth и не правится.

20. Короткая рабочая карта

bootstrap_hide.js
  creates FernwehContext.state.__RECTS__.__STATE__
  creates FernwehContext.state.__RECTS__.__CONFIG__.maxMeasurementScan

rects.js
  reads Core guard + PRNG
  reads screen state
  reads fonts config
  builds deterministic CSS/layout influence
  scans SVG and bounded DOM glyph/layout candidates
  applies inline style rules to generic measurement channels
  installs MutationObserver + microtask + timeout scans
  writes __RECTS__.__STATE__
  emits DEGRADE diagnostics
Chromium
  keeps native rect API
  computes layout/geometry normally
  returns native DOMRect / DOMRectList / SVG geometry results

Финальное правило:

RectsPatchModule управляет входами layout/rendering, а не выходами Web IDL rect API.