Жизнь пикселя: как интерфейсный код превращается через браузер в пиксели, отображаемые на экране.

внешний интерфейс JavaScript CSS OpenGL

Life of a Pixel изначально был учебным материалом для команды Chromium во время адаптации, его целью было дать возможность новым коллегам быстро понять архитектуру Chromium в целом, а не запутаться в логике кода. Теперь команда официально выпустила его, чтобы заинтересованные инженеры могли быстро разобраться в проекте и поучаствовать в разработке и совместной работе над проектом. Содержание этого видео, с точки зрения макроса, является названием этого выступления, Жизнь пикселя, Буквальный перевод - это жизнь пикселя, что означает, что автор речи надеется, что аудитория сможет понять после видео что код, выполненный фронтенд-инженерами, — это «Как превращаться в один пиксель за другим через браузер, и как пиксель обновляется и уничтожается».

Общий процесс

веб-контент (код) ➡️ магия (рендеринг) ➡️ пиксели (пиксели)

  • HTML (язык гипертекстовой разметки, структура и содержимое страницы)
  • CSS (каскадные таблицы стилей, стиль страницы)
  • JS (JavaScript, отвечает за обновление структуры страницы, контента и стиля страницы)

Содержимое, которое браузер фактически отображает, находится внутри красного прямоугольника, а остальная часть — это неотображаемая часть. Механизм рендеринга можно рассматривать как черный ящик, в Chromium мы называем его Blink.

При этом при рендеринге нам нужно вызвать базовый API обработки изображений для рендеринга, для этого официальным унифицированным стандартом является openGL, но для Windows может потребоваться и его конвертация в DirectX. Для этого команда работает над новым проектом под названием Vulkan для унификации. Конечно, этот низкоуровневый API не может читать наши HTML и CSS, они могут только делать некоторые простые изображения, такие как рисование нескольких полигонов.

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

первоначальный рендер

разбирать (разбирать)

DOM

Структура HTML представляет собой естественную структуру семантического наследования. Семантика обеспечивается метками, а интеграция обеспечивается древовидной структурой. Мы можем анализировать HTML в качестве входных данных и стать известным DOM-деревом. Хорошая интерпретация отношений между отцом и сыном, между братьями. Мы также можем найти его интуитивно из DOM API, предоставляемого JavaScript.

Style

Поскольку CSS является украшением HTML, он естественным образом связан с объектом DOM. Процесс прикрепления, то есть процесс выбора УСБ. Но из-за древовидной структуры HTML CSS иногда нужно писать очень сложно, чтобы эффективно сопоставить соответствующие элементы DOM.

При синтаксическом анализе CSS парсер сохранит имя атрибута CSS и значение атрибута, выбранное каждым селектором, в виде карты, при этом, как упоминалось в видео, имя атрибута CSS генерируется C++, а файл C++ генерируется python во время строительства.Скрипты генерируются автоматически. На следующем шаге, называемом recalc, для всех сгенерированных атрибутов мы вычисляем их наложенную сумму как значение каждого атрибута каждого элемента DOM, которое мы также называем вычисляемым значением. То есть финальная отрендеренная структура. Это значение свойства можно получить с помощью Chrome API или JavaScript DOM API.

Layout

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

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

Здесь вводится новая структура данных, которая также является дальнейшей инкапсуляцией Render Tree, полученной предыдущим пересчетом, далее рассматривается предыдущая сложная ситуация, и получается конечное положение каждого элемента на виде, то есть Layout Дерево. Следует отметить, что не каждый элемент DOM соответствует объекту макета, например, элементу, свойство display которого не установлено в none. В то же время не каждому Layout Object соответствует DOM-элемент, например псевдоэлемент.

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

Paint

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

Raster

Здесь мы получаем окончательную информацию об отображении элемента в представлении, и нам нужно фактически выполнить предварительный рендеринг. На этом шаге мы сгенерируем цвет каждого пикселя на экране в 32-битный двоичный код, представляющий 4 цвета соответственно.В то же время мы можем использовать GPU для ускорения рендеринга.Здесь также упоминается, что использование Собственная разработка Google. Проект skia выполняет рендеринг обработки изображений через самый низкий уровень OpenGL. При этом skia, как отдельный проект, поддерживает и другие масштабные проекты, например, систему Android.

gpu

Последнее, что следует отметить, это то, что API openGL, который на самом деле вызывается через skia, будет вызывать процесс GPU через CommandBuffer для реального рендеринга. То есть реальный рендеринг независим, и мы можем быстро перезапуститься, когда эта часть процесса выйдет из строя. При этом, как было сказано ранее, здесь мы будем конвертировать openGL в DirectX на платформе Windows через библиотеку Angle. Конечно, разработка Vulkan ведется для унификации, и в то же время разработчики также пытаются внедрить скии, вызывающие этот модуль, в процесс GPU.

Суммировать

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

обновление рендеринга

представлять

При обновлении рендеринга иногда масштабируем страницу, прокручивается область или есть анимация. В такой ситуации, если скорость рендеринга ниже 60 кадров в секунду, человеческий глаз увидит некоторое заикание.

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

Однако реальность такова, что иногда полностью меняется большая область, тогда нам приходится заново рендерить всю эту большую область, например прокручивать область.

Также следует отметить, что дизайн JavaScript является однопоточным, а это значит, что при рендеринге добавление выполнения JS-скриптов будет блокировать текущий рендеринг.

композитинг решений

Основываясь на проблемах, упомянутых ранее, команда Chromium придумала решение, называемое композитингом. Цель состоит в том, чтобы оптимизировать производительность. Немного похоже на фотошоп, проще говоря есть два момента:

  1. Страница разделена на независимые слои, и рендеринг между каждым слоем независим.
  2. Используйте отдельный поток (impl) для рендеринга слоя

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

При реализации концепции слоя структура данных исходного рендеринга, то есть дерево, по-прежнему называется деревом слоев. Он называется cc (композитор Chromium), а основная информация о данных наследуется от предыдущего дерева макетов. Обратите внимание, что существует также дерево PaintLayer, похожее на промежуточное состояние, которое накладывает слои на объект макета и дает ему такие функции, как обрезка дочерних элементов или применение других эффектов.

Естественно, мы добавим обновление композитинга в макет и этапы рисования, чтобы ускорить повторный рендеринг больших областей и получить дерево слоев. Следует отметить, что в настоящее время в команде выполняется проект под названием Slimming Paint. Создание дерева слоев находится после этапа рисования. Цель состоит в том, чтобы сделать создание каждого слоя более независимым, и установить дерево свойств. и извлеките Создать независимые или общедоступные свойства и поместите их до фактического рендеринга на уровне пикселей, насколько это возможно. Когда фаза рисования потока внедрения заканчивается, основной поток может быть уведомлен о синхронизации, что несколько похоже на использование git для слияния кода в разных ветвях.

Перед растром идет дальнейшая оптимизация.Для видов прокрутки большой площади не обязательно в начале конвертировать весь контент в битмапы.Нам нужно конвертировать только первый во вьюпорте.Здесь есть менеджер тайлов,который отвечающий за разделение области на блоки, такие как плитки на полу, будет отображать плитки в смежных областях предпочтительно при изменении области прокрутки.

Намечены все основные этапы. Добро пожаловать, чтобы добавить и углубить!

Спасибо Чжан Цзитао за организацию речи в статью и начало ее на Наггетс.