1 июл. 2018 г.

Какие действия заставляют Chromium вычислять layout (делать reflow)

Я уже как-то писал про то, какие действия заставляют WebKit в Chromium вычислять layout (делать reflow)

C тех пор Chromium перешёл на Blink, репозиторий кода сменил свой адрес, и вообще много чего изменилось. Настало время посмотреть в код ещё раз.



UI для просмотра кода и поиска по нему находится здесь: https://cs.chromium.org/chromium/src/third_party/blink/

С чего начать

Исходными точками будут уже знакомые методы и свойства, которые триггерили reflow ранее, и которые скорее всего будут это делать и сейчас. После пары попыток обнаруживается HTMLElement::offsetHeightForBinding() https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/html_element.cc?rcl=416c439d63601dac492fa6de9eb2fd649aefc14b&l=1296

Он вызывает методы

  • GetDocument().EnsurePaintLocationDataValidForNode(this)
  • HTMLElement::unclosedOffsetParent()
Они приводят нас в класс Document, в котором довольно много методов с подозрительными названиями, похожими на updateLayoutIgnorePendingStylesheets из предыдущего аналогичного исследования про WebKit:
  // Update ComputedStyles and attach LayoutObjects if necessary, but don't lay out.  void UpdateStyleAndLayoutTree();
  // Same as updateStyleAndLayoutTree() except ignoring pending stylesheets.
  void UpdateStyleAndLayoutTreeIgnorePendingStylesheets();
  void UpdateStyleAndLayoutTreeForNode(const Node*);
  void UpdateStyleAndLayout();
  void UpdateStyleAndLayoutIgnorePendingStylesheets(      RunPostLayoutTasks = kRunPostLayoutTasksAsyhnchronously);
  void UpdateStyleAndLayoutIgnorePendingStylesheetsForNode(Node*);

  // Ensures that location-based data will be valid for a given node.
  //
  // This will run style and layout if they are currently dirty, and it may also
  // run compositing inputs if the node is in a sticky subtree (as the sticky
  // offset may change the node's position).
  //
  // Due to this you should only call this if you definitely need valid location
  // data, otherwise use one of the |UpdateStyleAndLayout...| methods above.
  void EnsurePaintLocationDataValidForNode(const Node*);

Хорошо хоть, что название начинается одинаково - поищем по UpdateStyleAndLayout: https://cs.chromium.org/search/?q=UpdateStyleAndLayout+file:%5Esrc/third_party/blink/+package:%5Echromium$&m=100&sq=package:chromium&type=cs

UpdateStyleAndLayoutIgnorePendingStylesheetsForNode(this)

Что нашлось (я пропустил скорее всего нерелевантные места вроде тестов, отображения курсора и обработки событий мыши):

  • Element::OffsetParent, его далее используют методы Element::Offset{Left,Top,Width,Height}
  • Element::client{Left,Top,Width,Height} (есть тонкости в вызове на document)
  • Element::scroll{Left,Top,Width,Height}, setScroll{Left,Top} - вызывают UpdateStyleAndLayoutIgnorePendingStylesheetsForNode(this)
    только если элемент находится в активном документе (элемент не detached, документ уже инициализирован, но ещё не shutting down - тут надо разбираться, что это значит)
  • Element::scroll{By,To}, но есть пометка, что вызов будет удалён после http://crbug.com/420741
  • Element::innerText, Element::outerText

UpdateStyleAndLayoutTreeForNode(this)

  • Element::AttributeChanged - вызывает UpdateStyleAndLayoutTreeForNode(this) при изменении атрибута tabIndex у focused элемента - если после изменений элемент не может иметь фокус, то будет вызван blur()
  • ComputedStylePropertyMap::UpdateStyle, вызывается из ComputedStylePropertyMap::GetProperty
  • ElementAnimation::getAnimations - вызывается неизвестно откуда
  • HTMLLegendElement::focus
  • HTMLLabelElement::focus
  • CanvasRenderingContext2D::setFont, CanvasRenderingContext2D::direction, CanvasRenderingContext2D::measureText
  • CanvasRenderingContext2D::DrawTextInternal - вызывается из CanvasRenderingContext2D::fillText, CanvasRenderingContext2D::strokeText

UpdateStyleAndLayoutTree()

  • WebNode::IsContentEditable

UpdateStyleAndLayout()

  • ImageInputType::Height(), ImageInputType::Width() - если присутствует GetElement().GetLayoutObject() (что это - точно сказать не могу)
  • PaintLayerScrollableArea::Resize()

UpdateStyleAndLayoutTreeIgnorePendingStylesheets()

  • Element::focus - если элемент в активном документе, и на нём пока что нет фокуса, то будет вызван UpdateStyleAndLayoutTreeIgnorePendingStylesheets(), чтобы узнать, может ли элемент иметь фокус
  • Range::expand, Range::getClientRects, Range::BoundingRect
  • SVGPathElement::getTotalLength, SVGPathElement::getPointAtLength
  • MouseEvent::ComputeRelativePosition - если у мышиного события есть target, в свою очередь вызывается из MouseEvent::layerX, MouseEvent::layerY, MouseEvent::offsetX, MouseEvent::offsetY
  • SVGSVGElement::getIntersectionList, SVGSVGElement::getEnclosureList, SVGSVGElement::checkIntersection
  • ScrollManager::LogicalScroll(), ScrollManager::BubblingScroll(), ScrollManager::CustomizedScroll() - вызываются при скролле
  • DOMSelection::modify, DOMSelection::containsNode
  • DOMSelection::deleteFromDocument  https://www.w3.org/TR/selection-api/#dom-selection-deletefromdocument
  • SVGTextContentElement::getNumberOfChars, SVGTextContentElement::getComputedTextLength, SVGTextContentElement::getComputedTextLength
  • HTMLImageElement::width, HTMLImageElement::height - только если в активном документе
  • HTMLImageElement::x(), HTMLImageElement::y()
  • RadioInputType::HandleKeydownEvent - при перемещении стрелками на другой радиобаттон
  • SVGGeometryElement::isPointInFill, SVGGeometryElement::isPointInStroke, SVGGeometryElement::getTotalLength, SVGGeometryElement::getPointAtLength
  • DOMVisualViewport::pageLeft, DOMVisualViewport::pageTop
  • DOMVisualViewport::width, DOMVisualViewport::height - если не является главным фреймом, то пересчитываются стили для точного отображения скроллбаров
  • HTMLFormControlElement::reportValidity - перед установкой фокуса на невалидном элементе
  • CanvasRenderingContext2D::scrollPathIntoView, CanvasRenderingContext2D::drawFocusIfNeeded
  • CanvasRenderingContext2D::UpdateElementAccessibility - вызывается из CanvasRenderingContext2D::addHitRegion и CanvasRenderingContext2D::DrawFocusIfNeededInternal

EnsurePaintLocationDataValidForNode() (из него вызывается UpdateStyleAndLayoutTreeIgnorePendingStylesheets())

  • Element::scrollIntoView, Element::scrollIntoViewIfNeeded
  • Element::OffsetLeft, Element::OffsetTop, Element::OffsetWidth, Element::OffsetHeight
  • HTMLElement::offsetLeft{Top,Width,Height}ForBinding

Комментариев нет:

Отправить комментарий