arka triymfalnaya

blink layout [перевод]

Вольный перевод статьи из блога chromium.googlesource "Blink Layout"

Blink Layout

Директория Source/core/layout содержит реализацию объектов разметки. Покрывает следующие состояния жизненного цикла документа:

Заметьте, что ведется разработка новой Blink layout системы. Смотрите документ LayoutNG design document.

Код поддерживается командой layout team.

Блочная модель

Блочная модель CSS основана на серии вложенных блоков, от наружней к внутренней:

Следуя css-overflow-3, если скроллбары ничего не перекрывают, они должны быть внедрены между внутренней границей рамки (border) и внешней границей внутреннего отступа (padding).

График ниже был модифицирован на основе графика из спецификации блочной модели css, включая скроллбары:

|-------------------------------------------------| | | | margin-top | | | | |---------------------------------------| | | | | | | | border-top | | | | | | | | |--------------------------|--| | | | | | | | | | | | | padding-top |##| | | | | | |##| | | | | | |----------------| |##| | | | | | | | | | | | | ML | BL | PL | content box | PR |SW| BR | MR | | | | | | | | | | | | | |----------------| | | | | | | | | | | | | | | padding-bottom | | | | | | | | | | | | | |--------------------------|--| | | | | | scrollbar height ####|SC| | | | | |-----------------------------| | | | | | | | | border-bottom | | | | | | | |---------------------------------------| | | | | margin-bottom | | | |-------------------------------------------------|

BL = border-left BR = border-right ML = margin-left MR = margin-right PL = padding-left PR = padding-right SC = scroll corner SW = scrollbar width

Заметьте, что, в режиме горизонтального письма справа-налево, вертикальный скроллбар (если он существует) будет находиться слева. Горизонтальный скроллбар (если он существует), все время находится снизу.

Scroll origin vs. offset vs. position

Если LayoutBox имеет прокручиваемое переполнение (scrollable overflow), он ассоциируется с PaintLayerScrollableArea. Для представления положения верхней левой точки блока содержимого (видимой его части) в координатной системе, определенной верхней левой точкой переполняемого блока, в котором он может прокручиваться полностью к началу его содержимого, PaintLayerScrollableArea использует “начало прокрутки”.

Для содержимого, которое находится в потоке слева-направо и сверху-вниз, начало прокрутки будет в точке (0, 0), т.е. верхняя левая точка блока содержимого совпадает с верхней левой точкой содержимого переполняемого блока, в котором он может прокручиваться полностью к началу его содержимого.

Для содержимого, которое находится в потоке справа-налево (включая direction:ltr, writing-mode:vertical-rl и flex-direction:row-reverse), x-координата начала прокрутки будет положительной, а для содержимого, которое находится в потоке снизу-вверх (т.е., flex-direction:column-reverse и режим вертикального письма с direction:ltr), положительной будет y-координата.

Во всех случаях, термин ‘scrollOffset’ (или просто ‘offset’) использует тип ScrollOffset и обозначает расстояние прокрутки вьюпорта от его местоположения до начала его содержимого. Термин ‘scrollPosition’ (или просто ‘position’) использует тип FloatPoint и обозначает точку в координатной плоскости, определенную переполняемым блоком.

Визуализация этих концепций:

Alt Text Alt Text Alt Text

Если блок в потоке справа-налево и имеет скроллбар ортогонального направления (например, вертикальный скроллбар в блоке direction:rtl), размер скроллбара должен быть добавлен к вычислению начала прокрутки. Ниже представлены два примера. Заметьте, что не имеет значения, находится вертикальных скроллбар по правую или левую сторону блока (вертикальный скроллбар обозначен с помощью |/|):

блок содержимого |<-------->| начало прокрутки |----------->| _______________________ | |/| | | |/| | | |/| | direction:rtl | |/| блок | | |/| | | |/| | ||/||

переполняемый блок |<--------------------->|

блок содержимого |<-------->| начало прокрутки |----------->| _________________________ | | |/| | | |/| | | |/| writing-mode: | | блок |/| vertical-rl | | |/| | | |/| |__||/|

переполняемый блок |<--------------------->|

Координатные пространства

Layout и Paint работают с четырьмя координатными пространствами и часто обращаются к ним (на самом деле, к двум):

Пример с writing-mode: vertical-rl; direction: ltr:

'верхняя' / 'начальная' сторона

направление блочного потока <------------------------------------ | ------------------------------------- | | c | s | | 'левая' | o | o | | линейное 'правая' / | n | m | | направление / 'after' | t | e | | 'before' сторона | e | | | сторона | n | | | | t | | | ------------------------------------- v

'начальная' / 'конечная' сторона

Другом пример с элементом, имеющим относительное (relative) позиционирование:

<style>
	html {
		writing-mode: vertical-rl;
	}
</style>
<div
	id="container"
	style="background-color: lightBlue; width: 300px; height: 200px;"
>
	<div
		id="relpos"
		style="position: relative; top: 50px; left: -60px; width: 70px; height: 80px; background-color: red;"
	></div>
</div>

Их финальное расположение внутри фрейма с разрешением 800x600:

container: (492, 8 300x200) relpos: (662, 58 70x80)

Внешний отступ (margin) в 8px является дефолтным для HTML элемента body. согласно https://html.spec.whatwg.org/multipage/rendering.html#the-page.

Диаграмма ниже детально описывает размеры задействованных элементов:

Alt Text

На зарисовке ниже показан каждый шаг рекурсивного прохода к верхней границе документа:

LayoutBlockFlow (позиционирован относительно) DIV id='relpos' 0,0 70x80

Применить относительное позиционирование к 'relpos', пока происходит переворот внутри контейнера.

170 = 300 (ширина контейнера) - 70 (ширина relpos) - 60 (relpos left) 50 = relpos top

LayoutBlockFlow DIV id='container' 170,50 70x80

Поскольку body одной ширины с контейнером, переворот не влияет на блок на этом шаге.

LayoutBlockFlow BODY 170,50 70x80

Перевернуть внутри html блока, который симметрично больше body на 8px из-за дефолтного внешнего отступа.

LayoutBlockFlow HTML 178,58 70x80

Перевернуть блок в области просмотра.

662 = 800 (ширина области просмотра) - 316 (ширина html) + 178 (текущий left блока)

LayoutView #document 662,58 70x80

Поскольку относительно позиционированные элементы позиционируются с помощью физических координат, и переворот на каждом шаге отражает позицию, основанную на ширине блкоа контейнера, мы можем высчитать только финальные физические пикселы в пространстве экрана для относительно позиционированных элементов, если пройдем по всему layout дереву от начального объекта до самой верхней области видимости, как описано выше.

Дополнительные примеры режима письма и комбинаций направлений можно посмотреть здесь.

Перевернутые координаты блочного потока

Суть “переворачивания” значения в зеркальном его отражении внутри блока контейнера таким образом, что переворачивание его дважды приведет к изначальному положению. Таким образом, при работе с задействованной логиком может быть легко случайно перевернуть ненужное, поскольку переворот слишком много раз можно «исправить» еще одним переворотом. Очевидно, это может привести к запутанному и менее производительному коду, поэтому следует позаботиться о том, чтобы понять и задокументировать любые изменения в логике переворачивания.

Покрытие тестами Blink для возможностей режимов вертикальной записи и vertical-rl в частности может быть не настолько широким, как для режима горизонтальной записи. Имейте это ввиду, окгда пишете новую функциональность или тесты и обязательно включайте покрытие для всех режимов записи, когда это необходимо.

Значения обычно преобразуются в координаты перевернутого блочного потока с помощью набора методов на задействованных объектах разметки. Смотрите на FlipForWritingMode()FlipForWritingModeForChild().

InlineBox::FlipForWritingMode() переворачивает входное значение встроенного блока внутри контейнера.

LayoutBox::FlipForWritingMode() переворачивает входное значение указанного блока.

LayoutBox::FlipForWritingModeForChild() переворачивает входное значение указанного блока, компенсируя ширину и текущую x-позицию указанного дочернего блока. Это может быть полезным для частого шаблона, в котором мы строим точечное местоположение, начиная с текущего местоположения дочернего блока.

Классы и подклассы для LayoutBox и InlineBox:

Заметьте, что есть два основных похожих, но немного отличных метода для поиска содержащего блока для элемента:

В LayoutObject есть и другие методы для специальных целей, вроде фиксированного и абсолютного позиционирования и отмены рисования. Иногда код просто ссылается на элемент контейнера, который, к сожалению, можно понимать двояко, потому важно обратить пристальное внимание, какой метод использовался для получения контейнера.

Более сложные возможности веб платформы, вроде таблиц, flexboxа или мультиколоночности обычно реализуются поверх этих примитивов вместе с проверками IsFlippedBlocksWritingMode()IsLeftToRightDirection(), и IsHorizontalWritingMode(). Смотрите LayoutTableSection::LogicalRectForWritingModeAndDirection()LayoutFlexibleBox::UpdateAutoMarginsInCrossAxis() или LayoutMultiColumnFlowThread::FlowThreadTranslationAtPoint()`.

Geometry mapping

TODO(wkorman): Разработать:

Скроллинг

На данный момент уже имеется хороший обзор на скроллинг в Blink.

Скроллингом корневого уровня называется постоянный рефакторинг архитектуры скроллинга в Blink, который делает корневой PaintLayer ответственным за скроллинг, который раньше выполнялся с помощью FrameView. Больше деталей здесь Root Layer Scrolling.

Словарь

Здесь представлен краткий обзор на ключевые термины относительно блочного потока, внутристрочного потока и ориентации текста. Больше деталей здесь CSS Writing Modes Level 3.

Спецификация CSS Logical Properties Level 1 представляет последние идеи CSSWG относительно именования пространства логических координат. Когда ось подразумевается или не имеет значения, CSSWG опирается на block-startblock-endinline-start и inline-end, или на start и end .

Заметьте, что большинство кодовой базы Blink предшествует спецификации логических свойств и, таким образом, еще не последовательно ссылается на логическое направление в заявленном порядке, хотя мы хотели бы двигаться в этом направлении. Также взгляните на спецификацию physicalflow-relative и line-relative асбтрактной блочной терминологии.