1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2013, 2015 Apple Inc. All rights reserved.
7 * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#include "config.h"
26#include "RenderElement.h"
27
28#include "AXObjectCache.h"
29#include "ContentData.h"
30#include "CursorList.h"
31#include "ElementChildIterator.h"
32#include "EventHandler.h"
33#include "FocusController.h"
34#include "Frame.h"
35#include "FrameSelection.h"
36#include "HTMLAnchorElement.h"
37#include "HTMLBodyElement.h"
38#include "HTMLHtmlElement.h"
39#include "HTMLImageElement.h"
40#include "HTMLNames.h"
41#include "Logging.h"
42#include "Page.h"
43#include "PathUtilities.h"
44#include "RenderBlock.h"
45#include "RenderChildIterator.h"
46#include "RenderCounter.h"
47#include "RenderDeprecatedFlexibleBox.h"
48#include "RenderDescendantIterator.h"
49#include "RenderFlexibleBox.h"
50#include "RenderFragmentedFlow.h"
51#include "RenderGrid.h"
52#include "RenderImage.h"
53#include "RenderImageResourceStyleImage.h"
54#include "RenderInline.h"
55#include "RenderIterator.h"
56#include "RenderLayer.h"
57#include "RenderLayerCompositor.h"
58#include "RenderLineBreak.h"
59#include "RenderListItem.h"
60#if !ASSERT_DISABLED
61#include "RenderListMarker.h"
62#endif
63#include "RenderFragmentContainer.h"
64#include "RenderTableCaption.h"
65#include "RenderTableCell.h"
66#include "RenderTableCol.h"
67#include "RenderTableRow.h"
68#include "RenderText.h"
69#include "RenderTheme.h"
70#include "RenderTreeBuilder.h"
71#include "RenderView.h"
72#include "SVGImage.h"
73#include "SVGRenderSupport.h"
74#include "Settings.h"
75#include "ShadowRoot.h"
76#include "StylePendingResources.h"
77#include "StyleResolver.h"
78#include "TextAutoSizing.h"
79#include <wtf/IsoMallocInlines.h>
80#include <wtf/MathExtras.h>
81#include <wtf/StackStats.h>
82
83namespace WebCore {
84
85WTF_MAKE_ISO_ALLOCATED_IMPL(RenderElement);
86
87struct SameSizeAsRenderElement : public RenderObject {
88 unsigned bitfields : 25;
89 void* firstChild;
90 void* lastChild;
91 RenderStyle style;
92};
93
94static_assert(sizeof(RenderElement) == sizeof(SameSizeAsRenderElement), "RenderElement should stay small");
95
96inline RenderElement::RenderElement(ContainerNode& elementOrDocument, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
97 : RenderObject(elementOrDocument)
98 , m_baseTypeFlags(baseTypeFlags)
99 , m_ancestorLineBoxDirty(false)
100 , m_hasInitializedStyle(false)
101 , m_renderInlineAlwaysCreatesLineBoxes(false)
102 , m_renderBoxNeedsLazyRepaint(false)
103 , m_hasPausedImageAnimations(false)
104 , m_hasCounterNodeMap(false)
105 , m_hasContinuationChainNode(false)
106 , m_isContinuation(false)
107 , m_isFirstLetter(false)
108 , m_hasValidCachedFirstLineStyle(false)
109 , m_renderBlockHasMarginBeforeQuirk(false)
110 , m_renderBlockHasMarginAfterQuirk(false)
111 , m_renderBlockShouldForceRelayoutChildren(false)
112 , m_renderBlockFlowHasMarkupTruncation(false)
113 , m_renderBlockFlowLineLayoutPath(RenderBlockFlow::UndeterminedPath)
114 , m_isRegisteredForVisibleInViewportCallback(false)
115 , m_visibleInViewportState(static_cast<unsigned>(VisibleInViewportState::Unknown))
116 , m_firstChild(nullptr)
117 , m_lastChild(nullptr)
118 , m_style(WTFMove(style))
119{
120}
121
122RenderElement::RenderElement(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
123 : RenderElement(static_cast<ContainerNode&>(element), WTFMove(style), baseTypeFlags)
124{
125}
126
127RenderElement::RenderElement(Document& document, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
128 : RenderElement(static_cast<ContainerNode&>(document), WTFMove(style), baseTypeFlags)
129{
130}
131
132RenderElement::~RenderElement()
133{
134 // Do not add any code here. Add it to willBeDestroyed() instead.
135 ASSERT(!m_firstChild);
136}
137
138RenderPtr<RenderElement> RenderElement::createFor(Element& element, RenderStyle&& style, RendererCreationType creationType)
139{
140 // Minimal support for content properties replacing an entire element.
141 // Works only if we have exactly one piece of content and it's a URL.
142 // Otherwise acts as if we didn't support this feature.
143 const ContentData* contentData = style.contentData();
144 if (creationType == CreateAllRenderers && contentData && !contentData->next() && is<ImageContentData>(*contentData) && !element.isPseudoElement()) {
145 Style::loadPendingResources(style, element.document(), &element);
146 auto& styleImage = downcast<ImageContentData>(*contentData).image();
147 auto image = createRenderer<RenderImage>(element, WTFMove(style), const_cast<StyleImage*>(&styleImage));
148 image->setIsGeneratedContent();
149 return image;
150 }
151
152 switch (style.display()) {
153 case DisplayType::None:
154 case DisplayType::Contents:
155 return nullptr;
156 case DisplayType::Inline:
157 if (creationType == CreateAllRenderers)
158 return createRenderer<RenderInline>(element, WTFMove(style));
159 FALLTHROUGH; // Fieldsets should make a block flow if display:inline is set.
160 case DisplayType::Block:
161 case DisplayType::FlowRoot:
162 case DisplayType::InlineBlock:
163 case DisplayType::Compact:
164 return createRenderer<RenderBlockFlow>(element, WTFMove(style));
165 case DisplayType::ListItem:
166 return createRenderer<RenderListItem>(element, WTFMove(style));
167 case DisplayType::Flex:
168 case DisplayType::InlineFlex:
169 case DisplayType::WebKitFlex:
170 case DisplayType::WebKitInlineFlex:
171 return createRenderer<RenderFlexibleBox>(element, WTFMove(style));
172 case DisplayType::Grid:
173 case DisplayType::InlineGrid:
174 return createRenderer<RenderGrid>(element, WTFMove(style));
175 case DisplayType::Box:
176 case DisplayType::InlineBox:
177 return createRenderer<RenderDeprecatedFlexibleBox>(element, WTFMove(style));
178 default: {
179 if (creationType == OnlyCreateBlockAndFlexboxRenderers)
180 return createRenderer<RenderBlockFlow>(element, WTFMove(style));
181 switch (style.display()) {
182 case DisplayType::Table:
183 case DisplayType::InlineTable:
184 return createRenderer<RenderTable>(element, WTFMove(style));
185 case DisplayType::TableCell:
186 return createRenderer<RenderTableCell>(element, WTFMove(style));
187 case DisplayType::TableCaption:
188 return createRenderer<RenderTableCaption>(element, WTFMove(style));
189 case DisplayType::TableRowGroup:
190 case DisplayType::TableHeaderGroup:
191 case DisplayType::TableFooterGroup:
192 return createRenderer<RenderTableSection>(element, WTFMove(style));
193 case DisplayType::TableRow:
194 return createRenderer<RenderTableRow>(element, WTFMove(style));
195 case DisplayType::TableColumnGroup:
196 case DisplayType::TableColumn:
197 return createRenderer<RenderTableCol>(element, WTFMove(style));
198 default:
199 break;
200 }
201 break;
202 }
203 }
204 ASSERT_NOT_REACHED();
205 return nullptr;
206}
207
208std::unique_ptr<RenderStyle> RenderElement::computeFirstLineStyle() const
209{
210 ASSERT(view().usesFirstLineRules());
211
212 RenderElement& rendererForFirstLineStyle = isBeforeOrAfterContent() ? *parent() : const_cast<RenderElement&>(*this);
213
214 if (rendererForFirstLineStyle.isRenderBlockFlow() || rendererForFirstLineStyle.isRenderButton()) {
215 RenderBlock* firstLineBlock = rendererForFirstLineStyle.firstLineBlock();
216 if (!firstLineBlock)
217 return nullptr;
218 auto* firstLineStyle = firstLineBlock->getCachedPseudoStyle(PseudoId::FirstLine, &style());
219 if (!firstLineStyle)
220 return nullptr;
221 return RenderStyle::clonePtr(*firstLineStyle);
222 }
223
224 if (!rendererForFirstLineStyle.isRenderInline())
225 return nullptr;
226
227 auto& parentStyle = rendererForFirstLineStyle.parent()->firstLineStyle();
228 if (&parentStyle == &rendererForFirstLineStyle.parent()->style())
229 return nullptr;
230
231 if (rendererForFirstLineStyle.isAnonymous()) {
232 auto* textRendererWithDisplayContentsParent = RenderText::findByDisplayContentsInlineWrapperCandidate(rendererForFirstLineStyle);
233 if (!textRendererWithDisplayContentsParent)
234 return nullptr;
235 auto* composedTreeParentElement = textRendererWithDisplayContentsParent->textNode()->parentElementInComposedTree();
236 if (!composedTreeParentElement)
237 return nullptr;
238
239 auto style = composedTreeParentElement->styleResolver().styleForElement(*composedTreeParentElement, &parentStyle).renderStyle;
240 ASSERT(style->display() == DisplayType::Contents);
241
242 // We act as if there was an unstyled <span> around the text node. Only styling happens via inheritance.
243 auto firstLineStyle = RenderStyle::createPtr();
244 firstLineStyle->inheritFrom(*style);
245 return firstLineStyle;
246 }
247
248 return rendererForFirstLineStyle.element()->styleResolver().styleForElement(*element(), &parentStyle).renderStyle;
249}
250
251const RenderStyle& RenderElement::firstLineStyle() const
252{
253 if (!view().usesFirstLineRules())
254 return style();
255
256 if (!m_hasValidCachedFirstLineStyle) {
257 auto firstLineStyle = computeFirstLineStyle();
258 if (firstLineStyle || hasRareData())
259 const_cast<RenderElement&>(*this).ensureRareData().cachedFirstLineStyle = WTFMove(firstLineStyle);
260 m_hasValidCachedFirstLineStyle = true;
261 }
262
263 return (hasRareData() && rareData().cachedFirstLineStyle) ? *rareData().cachedFirstLineStyle : style();
264}
265
266StyleDifference RenderElement::adjustStyleDifference(StyleDifference diff, OptionSet<StyleDifferenceContextSensitiveProperty> contextSensitiveProperties) const
267{
268 // If transform changed, and we are not composited, need to do a layout.
269 if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Transform) {
270 // FIXME: when transforms are taken into account for overflow, we will need to do a layout.
271 if (!hasLayer() || !downcast<RenderLayerModelObject>(*this).layer()->isComposited()) {
272 if (!hasLayer())
273 diff = std::max(diff, StyleDifference::Layout);
274 else {
275 // We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set
276 // then we actually need SimplifiedLayoutAndPositionedMovement.
277 diff = std::max(diff, (diff == StyleDifference::LayoutPositionedMovementOnly) ? StyleDifference::SimplifiedLayoutAndPositionedMovement : StyleDifference::SimplifiedLayout);
278 }
279
280 } else
281 diff = std::max(diff, StyleDifference::RecompositeLayer);
282 }
283
284 if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Opacity) {
285 if (!hasLayer() || !downcast<RenderLayerModelObject>(*this).layer()->isComposited())
286 diff = std::max(diff, StyleDifference::RepaintLayer);
287 else
288 diff = std::max(diff, StyleDifference::RecompositeLayer);
289 }
290
291 if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::ClipPath) {
292 if (hasLayer()
293 && downcast<RenderLayerModelObject>(*this).layer()->isComposited()
294 && hasClipPath()
295 && RenderLayerCompositor::canCompositeClipPath(*downcast<RenderLayerModelObject>(*this).layer()))
296 diff = std::max(diff, StyleDifference::RecompositeLayer);
297 else
298 diff = std::max(diff, StyleDifference::Repaint);
299 }
300
301 if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::WillChange) {
302 if (style().willChange() && style().willChange()->canTriggerCompositing())
303 diff = std::max(diff, StyleDifference::RecompositeLayer);
304 }
305
306 if ((contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Filter) && hasLayer()) {
307 auto& layer = *downcast<RenderLayerModelObject>(*this).layer();
308 if (!layer.isComposited() || layer.paintsWithFilters())
309 diff = std::max(diff, StyleDifference::RepaintLayer);
310 else
311 diff = std::max(diff, StyleDifference::RecompositeLayer);
312 }
313
314 // The answer to requiresLayer() for plugins, iframes, and canvas can change without the actual
315 // style changing, since it depends on whether we decide to composite these elements. When the
316 // layer status of one of these elements changes, we need to force a layout.
317 if (diff < StyleDifference::Layout && isRenderLayerModelObject()) {
318 if (hasLayer() != downcast<RenderLayerModelObject>(*this).requiresLayer())
319 diff = StyleDifference::Layout;
320 }
321
322 // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
323 if (diff == StyleDifference::RepaintLayer && !hasLayer())
324 diff = StyleDifference::Repaint;
325
326 return diff;
327}
328
329inline bool RenderElement::hasImmediateNonWhitespaceTextChildOrBorderOrOutline() const
330{
331 for (auto& child : childrenOfType<RenderObject>(*this)) {
332 if (is<RenderText>(child) && !downcast<RenderText>(child).isAllCollapsibleWhitespace())
333 return true;
334 if (child.style().hasOutline() || child.style().hasBorder())
335 return true;
336 }
337 return false;
338}
339
340inline bool RenderElement::shouldRepaintForStyleDifference(StyleDifference diff) const
341{
342 return diff == StyleDifference::Repaint || (diff == StyleDifference::RepaintIfTextOrBorderOrOutline && hasImmediateNonWhitespaceTextChildOrBorderOrOutline());
343}
344
345void RenderElement::updateFillImages(const FillLayer* oldLayers, const FillLayer& newLayers)
346{
347 // Optimize the common case.
348 if (FillLayer::imagesIdentical(oldLayers, &newLayers))
349 return;
350
351 // Add before removing, to avoid removing all clients of an image that is in both sets.
352 for (auto* layer = &newLayers; layer; layer = layer->next()) {
353 if (layer->image())
354 layer->image()->addClient(this);
355 }
356 for (auto* layer = oldLayers; layer; layer = layer->next()) {
357 if (layer->image())
358 layer->image()->removeClient(this);
359 }
360}
361
362void RenderElement::updateImage(StyleImage* oldImage, StyleImage* newImage)
363{
364 if (oldImage == newImage)
365 return;
366 if (oldImage)
367 oldImage->removeClient(this);
368 if (newImage)
369 newImage->addClient(this);
370}
371
372void RenderElement::updateShapeImage(const ShapeValue* oldShapeValue, const ShapeValue* newShapeValue)
373{
374 if (oldShapeValue || newShapeValue)
375 updateImage(oldShapeValue ? oldShapeValue->image() : nullptr, newShapeValue ? newShapeValue->image() : nullptr);
376}
377
378void RenderElement::initializeStyle()
379{
380 Style::loadPendingResources(m_style, document(), element());
381
382 styleWillChange(StyleDifference::NewStyle, style());
383 m_hasInitializedStyle = true;
384 styleDidChange(StyleDifference::NewStyle, nullptr);
385
386 // We shouldn't have any text children that would need styleDidChange at this point.
387 ASSERT(!childrenOfType<RenderText>(*this).first());
388
389 // It would be nice to assert that !parent() here, but some RenderLayer subrenderers
390 // have their parent set before getting a call to initializeStyle() :|
391}
392
393void RenderElement::setStyle(RenderStyle&& style, StyleDifference minimalStyleDifference)
394{
395 // FIXME: Should change RenderView so it can use initializeStyle too.
396 // If we do that, we can assert m_hasInitializedStyle unconditionally,
397 // and remove the check of m_hasInitializedStyle below too.
398 ASSERT(m_hasInitializedStyle || isRenderView());
399
400 StyleDifference diff = StyleDifference::Equal;
401 OptionSet<StyleDifferenceContextSensitiveProperty> contextSensitiveProperties;
402 if (m_hasInitializedStyle)
403 diff = m_style.diff(style, contextSensitiveProperties);
404
405 diff = std::max(diff, minimalStyleDifference);
406
407 diff = adjustStyleDifference(diff, contextSensitiveProperties);
408
409 Style::loadPendingResources(style, document(), element());
410
411 styleWillChange(diff, style);
412 auto oldStyle = m_style.replace(WTFMove(style));
413 bool detachedFromParent = !parent();
414
415 // Make sure we invalidate the containing block cache for flows when the contianing block context changes
416 // so that styleDidChange can safely use RenderBlock::locateEnclosingFragmentedFlow()
417 if (oldStyle.position() != m_style.position())
418 adjustFragmentedFlowStateOnContainingBlockChangeIfNeeded();
419
420 styleDidChange(diff, &oldStyle);
421
422 // Text renderers use their parent style. Notify them about the change.
423 for (auto& child : childrenOfType<RenderText>(*this))
424 child.styleDidChange(diff, &oldStyle);
425
426 // FIXME: |this| might be destroyed here. This can currently happen for a RenderTextFragment when
427 // its first-letter block gets an update in RenderTextFragment::styleDidChange. For RenderTextFragment(s),
428 // we will safely bail out with the detachedFromParent flag. We might want to broaden this condition
429 // in the future as we move renderer changes out of layout and into style changes.
430 if (detachedFromParent)
431 return;
432
433 // Now that the layer (if any) has been updated, we need to adjust the diff again,
434 // check whether we should layout now, and decide if we need to repaint.
435 StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties);
436
437 if (diff <= StyleDifference::LayoutPositionedMovementOnly) {
438 if (updatedDiff == StyleDifference::Layout)
439 setNeedsLayoutAndPrefWidthsRecalc();
440 else if (updatedDiff == StyleDifference::LayoutPositionedMovementOnly)
441 setNeedsPositionedMovementLayout(&oldStyle);
442 else if (updatedDiff == StyleDifference::SimplifiedLayoutAndPositionedMovement) {
443 setNeedsPositionedMovementLayout(&oldStyle);
444 setNeedsSimplifiedNormalFlowLayout();
445 } else if (updatedDiff == StyleDifference::SimplifiedLayout)
446 setNeedsSimplifiedNormalFlowLayout();
447 }
448
449 if (updatedDiff == StyleDifference::RepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) {
450 // Do a repaint with the new style now, e.g., for example if we go from
451 // not having an outline to having an outline.
452 repaint();
453 }
454}
455
456void RenderElement::didAttachChild(RenderObject& child, RenderObject*)
457{
458 if (is<RenderText>(child))
459 downcast<RenderText>(child).styleDidChange(StyleDifference::Equal, nullptr);
460 // SVG creates renderers for <g display="none">, as SVG requires children of hidden
461 // <g>s to have renderers - at least that's how our implementation works. Consider:
462 // <g display="none"><foreignObject><body style="position: relative">FOO...
463 // - requiresLayer() would return true for the <body>, creating a new RenderLayer
464 // - when the document is painted, both layers are painted. The <body> layer doesn't
465 // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't.
466 // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree
467 // and stop creating layers at all for these cases - they're not used anyways.
468 if (child.hasLayer() && !layerCreationAllowedForSubtree())
469 downcast<RenderLayerModelObject>(child).layer()->removeOnlyThisLayer();
470}
471
472RenderObject* RenderElement::attachRendererInternal(RenderPtr<RenderObject> child, RenderObject* beforeChild)
473{
474 child->setParent(this);
475
476 if (m_firstChild == beforeChild)
477 m_firstChild = child.get();
478
479 if (beforeChild) {
480 auto* previousSibling = beforeChild->previousSibling();
481 if (previousSibling)
482 previousSibling->setNextSibling(child.get());
483 child->setPreviousSibling(previousSibling);
484 child->setNextSibling(beforeChild);
485 beforeChild->setPreviousSibling(child.get());
486 return child.release();
487 }
488 if (m_lastChild)
489 m_lastChild->setNextSibling(child.get());
490 child->setPreviousSibling(m_lastChild);
491 m_lastChild = child.get();
492 return child.release();
493}
494
495RenderPtr<RenderObject> RenderElement::detachRendererInternal(RenderObject& renderer)
496{
497 auto* parent = renderer.parent();
498 ASSERT(parent);
499 auto* nextSibling = renderer.nextSibling();
500
501 if (renderer.previousSibling())
502 renderer.previousSibling()->setNextSibling(nextSibling);
503 if (nextSibling)
504 nextSibling->setPreviousSibling(renderer.previousSibling());
505
506 if (parent->firstChild() == &renderer)
507 parent->m_firstChild = nextSibling;
508 if (parent->lastChild() == &renderer)
509 parent->m_lastChild = renderer.previousSibling();
510
511 renderer.setPreviousSibling(nullptr);
512 renderer.setNextSibling(nullptr);
513 renderer.setParent(nullptr);
514 return RenderPtr<RenderObject>(&renderer);
515}
516
517RenderBlock* RenderElement::containingBlockForFixedPosition() const
518{
519 auto* renderer = parent();
520 while (renderer && !renderer->canContainFixedPositionObjects())
521 renderer = renderer->parent();
522
523 ASSERT(!renderer || !renderer->isAnonymousBlock());
524 return downcast<RenderBlock>(renderer);
525}
526
527RenderBlock* RenderElement::containingBlockForAbsolutePosition() const
528{
529 // A relatively positioned RenderInline forwards its absolute positioned descendants to
530 // its nearest non-anonymous containing block (to avoid having a positioned objects list in all RenderInlines).
531 auto* renderer = isRenderInline() ? const_cast<RenderElement*>(downcast<RenderElement>(this)) : parent();
532 while (renderer && !renderer->canContainAbsolutelyPositionedObjects())
533 renderer = renderer->parent();
534 // Make sure we only return non-anonymous RenderBlock as containing block.
535 while (renderer && (!is<RenderBlock>(*renderer) || renderer->isAnonymousBlock()))
536 renderer = renderer->containingBlock();
537 return downcast<RenderBlock>(renderer);
538}
539
540static void addLayers(RenderElement& renderer, RenderLayer* parentLayer, RenderElement*& newObject, RenderLayer*& beforeChild)
541{
542 if (renderer.hasLayer()) {
543 if (!beforeChild && newObject) {
544 // We need to figure out the layer that follows newObject. We only do
545 // this the first time we find a child layer, and then we update the
546 // pointer values for newObject and beforeChild used by everyone else.
547 beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
548 newObject = nullptr;
549 }
550 parentLayer->addChild(*downcast<RenderLayerModelObject>(renderer).layer(), beforeChild);
551 return;
552 }
553
554 for (auto& child : childrenOfType<RenderElement>(renderer))
555 addLayers(child, parentLayer, newObject, beforeChild);
556}
557
558void RenderElement::addLayers(RenderLayer* parentLayer)
559{
560 if (!parentLayer)
561 return;
562
563 RenderElement* renderer = this;
564 RenderLayer* beforeChild = nullptr;
565 WebCore::addLayers(*this, parentLayer, renderer, beforeChild);
566}
567
568void RenderElement::removeLayers(RenderLayer* parentLayer)
569{
570 if (!parentLayer)
571 return;
572
573 if (hasLayer()) {
574 parentLayer->removeChild(*downcast<RenderLayerModelObject>(*this).layer());
575 return;
576 }
577
578 for (auto& child : childrenOfType<RenderElement>(*this))
579 child.removeLayers(parentLayer);
580}
581
582void RenderElement::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
583{
584 if (!newParent)
585 return;
586
587 if (hasLayer()) {
588 RenderLayer* layer = downcast<RenderLayerModelObject>(*this).layer();
589 ASSERT(oldParent == layer->parent());
590 if (oldParent)
591 oldParent->removeChild(*layer);
592 newParent->addChild(*layer);
593 return;
594 }
595
596 for (auto& child : childrenOfType<RenderElement>(*this))
597 child.moveLayers(oldParent, newParent);
598}
599
600RenderLayer* RenderElement::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent)
601{
602 // Error check the parent layer passed in. If it's null, we can't find anything.
603 if (!parentLayer)
604 return nullptr;
605
606 // Step 1: If our layer is a child of the desired parent, then return our layer.
607 RenderLayer* ourLayer = hasLayer() ? downcast<RenderLayerModelObject>(*this).layer() : nullptr;
608 if (ourLayer && ourLayer->parent() == parentLayer)
609 return ourLayer;
610
611 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
612 // into our siblings trying to find the next layer whose parent is the desired parent.
613 if (!ourLayer || ourLayer == parentLayer) {
614 for (RenderObject* child = startPoint ? startPoint->nextSibling() : firstChild(); child; child = child->nextSibling()) {
615 if (!is<RenderElement>(*child))
616 continue;
617 RenderLayer* nextLayer = downcast<RenderElement>(*child).findNextLayer(parentLayer, nullptr, false);
618 if (nextLayer)
619 return nextLayer;
620 }
621 }
622
623 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
624 // find anything.
625 if (parentLayer == ourLayer)
626 return nullptr;
627
628 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
629 // follow us to see if we can locate a layer.
630 if (checkParent && parent())
631 return parent()->findNextLayer(parentLayer, this, true);
632
633 return nullptr;
634}
635
636bool RenderElement::layerCreationAllowedForSubtree() const
637{
638 RenderElement* parentRenderer = parent();
639 while (parentRenderer) {
640 if (parentRenderer->isSVGHiddenContainer())
641 return false;
642 parentRenderer = parentRenderer->parent();
643 }
644
645 return true;
646}
647
648void RenderElement::propagateStyleToAnonymousChildren(StylePropagationType propagationType)
649{
650 // FIXME: We could save this call when the change only affected non-inherited properties.
651 for (auto& elementChild : childrenOfType<RenderElement>(*this)) {
652 if (!elementChild.isAnonymous() || elementChild.style().styleType() != PseudoId::None)
653 continue;
654
655 if (propagationType == PropagateToBlockChildrenOnly && !is<RenderBlock>(elementChild))
656 continue;
657
658#if ENABLE(FULLSCREEN_API)
659 if (elementChild.isRenderFullScreen() || elementChild.isRenderFullScreenPlaceholder())
660 continue;
661#endif
662
663 // RenderFragmentedFlows are updated through the RenderView::styleDidChange function.
664 if (is<RenderFragmentedFlow>(elementChild))
665 continue;
666
667 auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), elementChild.style().display());
668 if (style().specifiesColumns()) {
669 if (elementChild.style().specifiesColumns())
670 newStyle.inheritColumnPropertiesFrom(style());
671 if (elementChild.style().columnSpan() == ColumnSpan::All)
672 newStyle.setColumnSpan(ColumnSpan::All);
673 }
674
675 // Preserve the position style of anonymous block continuations as they can have relative or sticky position when
676 // they contain block descendants of relative or sticky positioned inlines.
677 if (elementChild.isInFlowPositioned() && elementChild.isContinuation())
678 newStyle.setPosition(elementChild.style().position());
679
680 updateAnonymousChildStyle(newStyle);
681
682 elementChild.setStyle(WTFMove(newStyle));
683 }
684}
685
686static inline bool rendererHasBackground(const RenderElement* renderer)
687{
688 return renderer && renderer->hasBackground();
689}
690
691void RenderElement::invalidateCachedFirstLineStyle()
692{
693 if (!m_hasValidCachedFirstLineStyle)
694 return;
695 m_hasValidCachedFirstLineStyle = false;
696 // Invalidate the subtree as descendant's first line style may depend on ancestor's.
697 for (auto& descendant : descendantsOfType<RenderElement>(*this))
698 descendant.m_hasValidCachedFirstLineStyle = false;
699}
700
701void RenderElement::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
702{
703 ASSERT(settings().shouldAllowUserInstalledFonts() || newStyle.fontDescription().shouldAllowUserInstalledFonts() == AllowUserInstalledFonts::No);
704
705 auto* oldStyle = hasInitializedStyle() ? &style() : nullptr;
706 if (oldStyle) {
707 // If our z-index changes value or our visibility changes,
708 // we need to dirty our stacking context's z-order list.
709 bool visibilityChanged = m_style.visibility() != newStyle.visibility()
710 || m_style.zIndex() != newStyle.zIndex()
711 || m_style.hasAutoZIndex() != newStyle.hasAutoZIndex();
712
713 if (visibilityChanged)
714 document().invalidateRenderingDependentRegions();
715
716 if (visibilityChanged) {
717 if (AXObjectCache* cache = document().existingAXObjectCache())
718 cache->childrenChanged(parent(), this);
719 }
720
721 // Keep layer hierarchy visibility bits up to date if visibility changes.
722 if (m_style.visibility() != newStyle.visibility()) {
723 if (RenderLayer* layer = enclosingLayer()) {
724 if (newStyle.visibility() == Visibility::Visible)
725 layer->setHasVisibleContent();
726 else if (layer->hasVisibleContent() && (this == &layer->renderer() || layer->renderer().style().visibility() != Visibility::Visible)) {
727 layer->dirtyVisibleContentStatus();
728 if (diff > StyleDifference::RepaintLayer)
729 repaint();
730 }
731 }
732 }
733
734 auto needsInvalidateEventRegion = [&] {
735 if (m_style.pointerEvents() != newStyle.pointerEvents())
736 return true;
737#if ENABLE(POINTER_EVENTS)
738 if (m_style.effectiveTouchActions() != newStyle.effectiveTouchActions())
739 return true;
740#endif
741 return false;
742 };
743
744 if (needsInvalidateEventRegion()) {
745 // Usually the event region gets updated as a result of paint invalidation. Here we need to request an update explicitly.
746 if (auto* layer = enclosingLayer())
747 layer->invalidateEventRegion();
748 }
749
750 if (m_parent && (newStyle.outlineSize() < m_style.outlineSize() || shouldRepaintForStyleDifference(diff)))
751 repaint();
752
753 if (isFloating() && m_style.floating() != newStyle.floating()) {
754 // For changes in float styles, we need to conceivably remove ourselves
755 // from the floating objects list.
756 downcast<RenderBox>(*this).removeFloatingOrPositionedChildFromBlockLists();
757 } else if (isOutOfFlowPositioned() && m_style.position() != newStyle.position()) {
758 // For changes in positioning styles, we need to conceivably remove ourselves
759 // from the positioned objects list.
760 downcast<RenderBox>(*this).removeFloatingOrPositionedChildFromBlockLists();
761 }
762
763 // reset style flags
764 if (diff == StyleDifference::Layout || diff == StyleDifference::LayoutPositionedMovementOnly) {
765 setFloating(false);
766 clearPositionedState();
767 }
768 if (newStyle.hasPseudoStyle(PseudoId::FirstLine) || oldStyle->hasPseudoStyle(PseudoId::FirstLine))
769 invalidateCachedFirstLineStyle();
770
771 setHorizontalWritingMode(true);
772 setHasVisibleBoxDecorations(false);
773 setHasOverflowClip(false);
774 setHasTransformRelatedProperty(false);
775 setHasReflection(false);
776 }
777
778 bool newStyleSlowScroll = false;
779 if (newStyle.hasFixedBackgroundImage() && !settings().fixedBackgroundsPaintRelativeToDocument()) {
780 newStyleSlowScroll = true;
781 bool drawsRootBackground = isDocumentElementRenderer() || (isBody() && !rendererHasBackground(document().documentElement()->renderer()));
782 if (drawsRootBackground && newStyle.hasEntirelyFixedBackground() && view().compositor().supportsFixedRootBackgroundCompositing())
783 newStyleSlowScroll = false;
784 }
785
786 if (view().frameView().hasSlowRepaintObject(*this)) {
787 if (!newStyleSlowScroll)
788 view().frameView().removeSlowRepaintObject(*this);
789 } else if (newStyleSlowScroll)
790 view().frameView().addSlowRepaintObject(*this);
791
792 if (isDocumentElementRenderer() || isBody())
793 view().frameView().updateExtendBackgroundIfNecessary();
794}
795
796#if !PLATFORM(IOS_FAMILY)
797static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b)
798{
799 ASSERT(a->cursors() != b->cursors());
800 return a->cursors() && b->cursors() && *a->cursors() == *b->cursors();
801}
802
803static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b)
804{
805 return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b));
806}
807#endif
808
809void RenderElement::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
810{
811 updateFillImages(oldStyle ? &oldStyle->backgroundLayers() : nullptr, m_style.backgroundLayers());
812 updateFillImages(oldStyle ? &oldStyle->maskLayers() : nullptr, m_style.maskLayers());
813 updateImage(oldStyle ? oldStyle->borderImage().image() : nullptr, m_style.borderImage().image());
814 updateImage(oldStyle ? oldStyle->maskBoxImage().image() : nullptr, m_style.maskBoxImage().image());
815 updateShapeImage(oldStyle ? oldStyle->shapeOutside() : nullptr, m_style.shapeOutside());
816
817 SVGRenderSupport::styleChanged(*this, oldStyle);
818
819 if (!m_parent)
820 return;
821
822 if (diff == StyleDifference::Layout || diff == StyleDifference::SimplifiedLayout) {
823 RenderCounter::rendererStyleChanged(*this, oldStyle, &m_style);
824
825 // If the object already needs layout, then setNeedsLayout won't do
826 // any work. But if the containing block has changed, then we may need
827 // to mark the new containing blocks for layout. The change that can
828 // directly affect the containing block of this object is a change to
829 // the position style.
830 if (needsLayout() && oldStyle->position() != m_style.position())
831 markContainingBlocksForLayout();
832
833 if (diff == StyleDifference::Layout)
834 setNeedsLayoutAndPrefWidthsRecalc();
835 else
836 setNeedsSimplifiedNormalFlowLayout();
837 } else if (diff == StyleDifference::SimplifiedLayoutAndPositionedMovement) {
838 setNeedsPositionedMovementLayout(oldStyle);
839 setNeedsSimplifiedNormalFlowLayout();
840 } else if (diff == StyleDifference::LayoutPositionedMovementOnly)
841 setNeedsPositionedMovementLayout(oldStyle);
842
843 // Don't check for repaint here; we need to wait until the layer has been
844 // updated by subclasses before we know if we have to repaint (in setStyle()).
845
846#if !PLATFORM(IOS_FAMILY)
847 if (oldStyle && !areCursorsEqual(oldStyle, &style()))
848 frame().eventHandler().scheduleCursorUpdate();
849#endif
850 bool hadOutlineAuto = oldStyle && oldStyle->outlineStyleIsAuto() == OutlineIsAuto::On;
851 bool hasOutlineAuto = outlineStyleForRepaint().outlineStyleIsAuto() == OutlineIsAuto::On;
852 if (hasOutlineAuto != hadOutlineAuto) {
853 updateOutlineAutoAncestor(hasOutlineAuto);
854 issueRepaintForOutlineAuto(hasOutlineAuto ? outlineStyleForRepaint().outlineSize() : oldStyle->outlineSize());
855 }
856}
857
858void RenderElement::insertedIntoTree()
859{
860 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
861 // and don't have a layer attached to ourselves.
862 RenderLayer* layer = nullptr;
863 if (firstChild() || hasLayer()) {
864 layer = parent()->enclosingLayer();
865 addLayers(layer);
866 }
867
868 // If |this| is visible but this object was not, tell the layer it has some visible content
869 // that needs to be drawn and layer visibility optimization can't be used
870 if (parent()->style().visibility() != Visibility::Visible && style().visibility() == Visibility::Visible && !hasLayer()) {
871 if (!layer)
872 layer = parent()->enclosingLayer();
873 if (layer)
874 layer->setHasVisibleContent();
875 }
876
877 RenderObject::insertedIntoTree();
878}
879
880void RenderElement::willBeRemovedFromTree()
881{
882 // If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
883 RenderLayer* layer = nullptr;
884 if (parent()->style().visibility() != Visibility::Visible && style().visibility() == Visibility::Visible && !hasLayer()) {
885 if ((layer = parent()->enclosingLayer()))
886 layer->dirtyVisibleContentStatus();
887 }
888 // Keep our layer hierarchy updated.
889 if (firstChild() || hasLayer()) {
890 if (!layer)
891 layer = parent()->enclosingLayer();
892 removeLayers(layer);
893 }
894
895 if (isOutOfFlowPositioned() && parent()->childrenInline())
896 parent()->dirtyLinesFromChangedChild(*this);
897
898 RenderObject::willBeRemovedFromTree();
899}
900
901inline void RenderElement::clearSubtreeLayoutRootIfNeeded() const
902{
903 if (renderTreeBeingDestroyed())
904 return;
905
906 if (view().frameView().layoutContext().subtreeLayoutRoot() != this)
907 return;
908
909 // Normally when a renderer is detached from the tree, the appropriate dirty bits get set
910 // which ensures that this renderer is no longer the layout root.
911 ASSERT_NOT_REACHED();
912
913 // This indicates a failure to layout the child, which is why
914 // the layout root is still set to |this|. Make sure to clear it
915 // since we are getting destroyed.
916 view().frameView().layoutContext().clearSubtreeLayoutRoot();
917}
918
919void RenderElement::willBeDestroyed()
920{
921 if (m_style.hasFixedBackgroundImage() && !settings().fixedBackgroundsPaintRelativeToDocument())
922 view().frameView().removeSlowRepaintObject(*this);
923
924 unregisterForVisibleInViewportCallback();
925
926 if (hasCounterNodeMap())
927 RenderCounter::destroyCounterNodes(*this);
928
929 RenderObject::willBeDestroyed();
930
931 clearSubtreeLayoutRootIfNeeded();
932
933 if (hasInitializedStyle()) {
934 for (auto* bgLayer = &m_style.backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) {
935 if (auto* backgroundImage = bgLayer->image())
936 backgroundImage->removeClient(this);
937 }
938 for (auto* maskLayer = &m_style.maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
939 if (auto* maskImage = maskLayer->image())
940 maskImage->removeClient(this);
941 }
942 if (auto* borderImage = m_style.borderImage().image())
943 borderImage->removeClient(this);
944 if (auto* maskBoxImage = m_style.maskBoxImage().image())
945 maskBoxImage->removeClient(this);
946 if (auto shapeValue = m_style.shapeOutside()) {
947 if (auto shapeImage = shapeValue->image())
948 shapeImage->removeClient(this);
949 }
950 }
951 if (m_hasPausedImageAnimations)
952 view().removeRendererWithPausedImageAnimations(*this);
953}
954
955void RenderElement::setNeedsPositionedMovementLayout(const RenderStyle* oldStyle)
956{
957 ASSERT(!isSetNeedsLayoutForbidden());
958 if (needsPositionedMovementLayout())
959 return;
960 setNeedsPositionedMovementLayoutBit(true);
961 markContainingBlocksForLayout();
962 if (hasLayer()) {
963 if (oldStyle && style().diffRequiresLayerRepaint(*oldStyle, downcast<RenderLayerModelObject>(*this).layer()->isComposited()))
964 setLayerNeedsFullRepaint();
965 else
966 setLayerNeedsFullRepaintForPositionedMovementLayout();
967 }
968}
969
970void RenderElement::clearChildNeedsLayout()
971{
972 setNormalChildNeedsLayoutBit(false);
973 setPosChildNeedsLayoutBit(false);
974 setNeedsSimplifiedNormalFlowLayoutBit(false);
975 setNormalChildNeedsLayoutBit(false);
976 setNeedsPositionedMovementLayoutBit(false);
977}
978
979void RenderElement::setNeedsSimplifiedNormalFlowLayout()
980{
981 ASSERT(!isSetNeedsLayoutForbidden());
982 if (needsSimplifiedNormalFlowLayout())
983 return;
984 setNeedsSimplifiedNormalFlowLayoutBit(true);
985 markContainingBlocksForLayout();
986 if (hasLayer())
987 setLayerNeedsFullRepaint();
988}
989
990static inline void paintPhase(RenderElement& element, PaintPhase phase, PaintInfo& paintInfo, const LayoutPoint& childPoint)
991{
992 paintInfo.phase = phase;
993 element.paint(paintInfo, childPoint);
994}
995
996void RenderElement::paintAsInlineBlock(PaintInfo& paintInfo, const LayoutPoint& childPoint)
997{
998 // Paint all phases atomically, as though the element established its own stacking context.
999 // (See Appendix E.2, section 6.4 on inline block/table/replaced elements in the CSS2.1 specification.)
1000 // This is also used by other elements (e.g. flex items and grid items).
1001 PaintPhase paintPhaseToUse = isExcludedAndPlacedInBorder() ? paintInfo.phase : PaintPhase::Foreground;
1002 if (paintInfo.phase == PaintPhase::Selection || paintInfo.phase == PaintPhase::EventRegion)
1003 paint(paintInfo, childPoint);
1004 else if (paintInfo.phase == paintPhaseToUse) {
1005 paintPhase(*this, PaintPhase::BlockBackground, paintInfo, childPoint);
1006 paintPhase(*this, PaintPhase::ChildBlockBackgrounds, paintInfo, childPoint);
1007 paintPhase(*this, PaintPhase::Float, paintInfo, childPoint);
1008 paintPhase(*this, PaintPhase::Foreground, paintInfo, childPoint);
1009 paintPhase(*this, PaintPhase::Outline, paintInfo, childPoint);
1010
1011 // Reset |paintInfo| to the original phase.
1012 paintInfo.phase = paintPhaseToUse;
1013 }
1014}
1015
1016void RenderElement::layout()
1017{
1018 StackStats::LayoutCheckPoint layoutCheckPoint;
1019 ASSERT(needsLayout());
1020 for (auto* child = firstChild(); child; child = child->nextSibling()) {
1021 if (child->needsLayout())
1022 downcast<RenderElement>(*child).layout();
1023 ASSERT(!child->needsLayout());
1024 }
1025 clearNeedsLayout();
1026}
1027
1028static bool mustRepaintFillLayers(const RenderElement& renderer, const FillLayer& layer)
1029{
1030 // Nobody will use multiple layers without wanting fancy positioning.
1031 if (layer.next())
1032 return true;
1033
1034 // Make sure we have a valid image.
1035 auto* image = layer.image();
1036 if (!image || !image->canRender(&renderer, renderer.style().effectiveZoom()))
1037 return false;
1038
1039 if (!layer.xPosition().isZero() || !layer.yPosition().isZero())
1040 return true;
1041
1042 auto sizeType = layer.sizeType();
1043
1044 if (sizeType == FillSizeType::Contain || sizeType == FillSizeType::Cover)
1045 return true;
1046
1047 if (sizeType == FillSizeType::Size) {
1048 auto size = layer.sizeLength();
1049 if (size.width.isPercentOrCalculated() || size.height.isPercentOrCalculated())
1050 return true;
1051 // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
1052 if ((size.width.isAuto() || size.height.isAuto()) && image->isGeneratedImage())
1053 return true;
1054 } else if (image->usesImageContainerSize())
1055 return true;
1056
1057 return false;
1058}
1059
1060static bool mustRepaintBackgroundOrBorder(const RenderElement& renderer)
1061{
1062 if (renderer.hasMask() && mustRepaintFillLayers(renderer, renderer.style().maskLayers()))
1063 return true;
1064
1065 // If we don't have a background/border/mask, then nothing to do.
1066 if (!renderer.hasVisibleBoxDecorations())
1067 return false;
1068
1069 if (mustRepaintFillLayers(renderer, renderer.style().backgroundLayers()))
1070 return true;
1071
1072 // Our fill layers are ok. Let's check border.
1073 if (renderer.style().hasBorder() && renderer.borderImageIsLoadedAndCanBeRendered())
1074 return true;
1075
1076 return false;
1077}
1078
1079bool RenderElement::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr, const LayoutRect* newOutlineBoxRectPtr)
1080{
1081 if (view().printing())
1082 return false; // Don't repaint if we're printing.
1083
1084 // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048
1085 // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer));
1086 LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer);
1087 LayoutRect newOutlineBox;
1088
1089 bool fullRepaint = selfNeedsLayout();
1090 // Presumably a background or a border exists if border-fit:lines was specified.
1091 if (!fullRepaint && style().borderFit() == BorderFit::Lines)
1092 fullRepaint = true;
1093 if (!fullRepaint) {
1094 // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048
1095 // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer));
1096 newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer);
1097 fullRepaint = (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder(*this) && (newBounds != oldBounds || newOutlineBox != oldOutlineBox)));
1098 }
1099
1100 if (!repaintContainer)
1101 repaintContainer = &view();
1102
1103 if (fullRepaint) {
1104 repaintUsingContainer(repaintContainer, oldBounds);
1105 if (newBounds != oldBounds)
1106 repaintUsingContainer(repaintContainer, newBounds);
1107 return true;
1108 }
1109
1110 if (newBounds == oldBounds && newOutlineBox == oldOutlineBox)
1111 return false;
1112
1113 LayoutUnit deltaLeft = newBounds.x() - oldBounds.x();
1114 if (deltaLeft > 0)
1115 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height()));
1116 else if (deltaLeft < 0)
1117 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height()));
1118
1119 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX();
1120 if (deltaRight > 0)
1121 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()));
1122 else if (deltaRight < 0)
1123 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height()));
1124
1125 LayoutUnit deltaTop = newBounds.y() - oldBounds.y();
1126 if (deltaTop > 0)
1127 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop));
1128 else if (deltaTop < 0)
1129 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop));
1130
1131 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY();
1132 if (deltaBottom > 0)
1133 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom));
1134 else if (deltaBottom < 0)
1135 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom));
1136
1137 if (newOutlineBox == oldOutlineBox)
1138 return false;
1139
1140 // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly
1141 // two rectangles (but typically only one).
1142 const RenderStyle& outlineStyle = outlineStyleForRepaint();
1143 LayoutUnit outlineWidth = outlineStyle.outlineSize();
1144 LayoutBoxExtent insetShadowExtent = style().getBoxShadowInsetExtent();
1145 LayoutUnit width = absoluteValue(newOutlineBox.width() - oldOutlineBox.width());
1146 if (width) {
1147 LayoutUnit shadowLeft;
1148 LayoutUnit shadowRight;
1149 style().getBoxShadowHorizontalExtent(shadowLeft, shadowRight);
1150 LayoutUnit borderRight = is<RenderBox>(*this) ? downcast<RenderBox>(*this).borderRight() : 0_lu;
1151 LayoutUnit boxWidth = is<RenderBox>(*this) ? downcast<RenderBox>(*this).width() : 0_lu;
1152 LayoutUnit minInsetRightShadowExtent = std::min<LayoutUnit>(-insetShadowExtent.right(), std::min(newBounds.width(), oldBounds.width()));
1153 LayoutUnit borderWidth = std::max(borderRight, std::max(valueForLength(style().borderTopRightRadius().width, boxWidth), valueForLength(style().borderBottomRightRadius().width, boxWidth)));
1154 LayoutUnit decorationsWidth = std::max<LayoutUnit>(-outlineStyle.outlineOffset(), borderWidth + minInsetRightShadowExtent) + std::max(outlineWidth, shadowRight);
1155 LayoutRect rightRect(newOutlineBox.x() + std::min(newOutlineBox.width(), oldOutlineBox.width()) - decorationsWidth,
1156 newOutlineBox.y(),
1157 width + decorationsWidth,
1158 std::max(newOutlineBox.height(), oldOutlineBox.height()));
1159 LayoutUnit right = std::min(newBounds.maxX(), oldBounds.maxX());
1160 if (rightRect.x() < right) {
1161 rightRect.setWidth(std::min(rightRect.width(), right - rightRect.x()));
1162 repaintUsingContainer(repaintContainer, rightRect);
1163 }
1164 }
1165 LayoutUnit height = absoluteValue(newOutlineBox.height() - oldOutlineBox.height());
1166 if (height) {
1167 LayoutUnit shadowTop;
1168 LayoutUnit shadowBottom;
1169 style().getBoxShadowVerticalExtent(shadowTop, shadowBottom);
1170 LayoutUnit borderBottom = is<RenderBox>(*this) ? downcast<RenderBox>(*this).borderBottom() : 0_lu;
1171 LayoutUnit boxHeight = is<RenderBox>(*this) ? downcast<RenderBox>(*this).height() : 0_lu;
1172 LayoutUnit minInsetBottomShadowExtent = std::min<LayoutUnit>(-insetShadowExtent.bottom(), std::min(newBounds.height(), oldBounds.height()));
1173 LayoutUnit borderHeight = std::max(borderBottom, std::max(valueForLength(style().borderBottomLeftRadius().height, boxHeight),
1174 valueForLength(style().borderBottomRightRadius().height, boxHeight)));
1175 LayoutUnit decorationsHeight = std::max<LayoutUnit>(-outlineStyle.outlineOffset(), borderHeight + minInsetBottomShadowExtent) + std::max(outlineWidth, shadowBottom);
1176 LayoutRect bottomRect(newOutlineBox.x(),
1177 std::min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - decorationsHeight,
1178 std::max(newOutlineBox.width(), oldOutlineBox.width()),
1179 height + decorationsHeight);
1180 LayoutUnit bottom = std::min(newBounds.maxY(), oldBounds.maxY());
1181 if (bottomRect.y() < bottom) {
1182 bottomRect.setHeight(std::min(bottomRect.height(), bottom - bottomRect.y()));
1183 repaintUsingContainer(repaintContainer, bottomRect);
1184 }
1185 }
1186 return false;
1187}
1188
1189bool RenderElement::borderImageIsLoadedAndCanBeRendered() const
1190{
1191 ASSERT(style().hasBorder());
1192
1193 StyleImage* borderImage = style().borderImage().image();
1194 return borderImage && borderImage->canRender(this, style().effectiveZoom()) && borderImage->isLoaded();
1195}
1196
1197bool RenderElement::mayCauseRepaintInsideViewport(const IntRect* optionalViewportRect) const
1198{
1199 auto& frameView = view().frameView();
1200 if (frameView.isOffscreen())
1201 return false;
1202
1203 if (!hasOverflowClip()) {
1204 // FIXME: Computing the overflow rect is expensive if any descendant has
1205 // its own self-painting layer. As a result, we prefer to abort early in
1206 // this case and assume it may cause us to repaint inside the viewport.
1207 if (!hasLayer() || downcast<RenderLayerModelObject>(*this).layer()->firstChild())
1208 return true;
1209 }
1210
1211 // Compute viewport rect if it was not provided.
1212 const IntRect& visibleRect = optionalViewportRect ? *optionalViewportRect : frameView.windowToContents(frameView.windowClipRect());
1213 return visibleRect.intersects(enclosingIntRect(absoluteClippedOverflowRect()));
1214}
1215
1216bool RenderElement::isVisibleInDocumentRect(const IntRect& documentRect) const
1217{
1218 if (document().activeDOMObjectsAreSuspended())
1219 return false;
1220 if (style().visibility() != Visibility::Visible)
1221 return false;
1222 if (view().frameView().isOffscreen())
1223 return false;
1224
1225 // Use background rect if we are the root or if we are the body and the background is propagated to the root.
1226 // FIXME: This is overly conservative as the image may not be a background-image, in which case it will not
1227 // be propagated to the root. At this point, we unfortunately don't have access to the image anymore so we
1228 // can no longer check if it is a background image.
1229 bool backgroundIsPaintedByRoot = isDocumentElementRenderer();
1230 if (isBody()) {
1231 auto& rootRenderer = *parent(); // If <body> has a renderer then <html> does too.
1232 ASSERT(rootRenderer.isDocumentElementRenderer());
1233 ASSERT(is<HTMLHtmlElement>(rootRenderer.element()));
1234 // FIXME: Should share body background propagation code.
1235 backgroundIsPaintedByRoot = !rootRenderer.hasBackground();
1236
1237 }
1238
1239 LayoutRect backgroundPaintingRect = backgroundIsPaintedByRoot ? view().backgroundRect() : absoluteClippedOverflowRect();
1240 if (!documentRect.intersects(enclosingIntRect(backgroundPaintingRect)))
1241 return false;
1242
1243 return true;
1244}
1245
1246void RenderElement::registerForVisibleInViewportCallback()
1247{
1248 if (m_isRegisteredForVisibleInViewportCallback)
1249 return;
1250 m_isRegisteredForVisibleInViewportCallback = true;
1251
1252 view().registerForVisibleInViewportCallback(*this);
1253}
1254
1255void RenderElement::unregisterForVisibleInViewportCallback()
1256{
1257 if (!m_isRegisteredForVisibleInViewportCallback)
1258 return;
1259 m_isRegisteredForVisibleInViewportCallback = false;
1260
1261 view().unregisterForVisibleInViewportCallback(*this);
1262}
1263
1264void RenderElement::setVisibleInViewportState(VisibleInViewportState state)
1265{
1266 if (state == visibleInViewportState())
1267 return;
1268 m_visibleInViewportState = static_cast<unsigned>(state);
1269 visibleInViewportStateChanged();
1270}
1271
1272void RenderElement::visibleInViewportStateChanged()
1273{
1274 ASSERT_NOT_REACHED();
1275}
1276
1277bool RenderElement::isVisibleInViewport() const
1278{
1279 auto& frameView = view().frameView();
1280 auto visibleRect = frameView.windowToContents(frameView.windowClipRect());
1281 return isVisibleInDocumentRect(visibleRect);
1282}
1283
1284VisibleInViewportState RenderElement::imageFrameAvailable(CachedImage& image, ImageAnimatingState animatingState, const IntRect* changeRect)
1285{
1286 bool isVisible = isVisibleInViewport();
1287
1288 if (!isVisible && animatingState == ImageAnimatingState::Yes)
1289 view().addRendererWithPausedImageAnimations(*this, image);
1290
1291 // Static images should repaint even if they are outside the viewport rectangle
1292 // because they should be inside the TileCoverageRect.
1293 if (isVisible || animatingState == ImageAnimatingState::No)
1294 imageChanged(&image, changeRect);
1295
1296 if (element() && image.image()->isBitmapImage())
1297 element()->dispatchWebKitImageReadyEventForTesting();
1298
1299 return isVisible ? VisibleInViewportState::Yes : VisibleInViewportState::No;
1300}
1301
1302void RenderElement::didRemoveCachedImageClient(CachedImage& cachedImage)
1303{
1304 if (hasPausedImageAnimations())
1305 view().removeRendererWithPausedImageAnimations(*this, cachedImage);
1306}
1307
1308bool RenderElement::repaintForPausedImageAnimationsIfNeeded(const IntRect& visibleRect, CachedImage& cachedImage)
1309{
1310 ASSERT(m_hasPausedImageAnimations);
1311 if (!isVisibleInDocumentRect(visibleRect))
1312 return false;
1313
1314 repaint();
1315
1316 if (auto* image = cachedImage.image()) {
1317 if (is<SVGImage>(image))
1318 downcast<SVGImage>(image)->scheduleStartAnimation();
1319 else
1320 image->startAnimation();
1321 }
1322
1323 // For directly-composited animated GIFs it does not suffice to call repaint() to resume animation. We need to mark the image as changed.
1324 if (is<RenderBoxModelObject>(*this))
1325 downcast<RenderBoxModelObject>(*this).contentChanged(ImageChanged);
1326
1327 return true;
1328}
1329
1330const RenderStyle* RenderElement::getCachedPseudoStyle(PseudoId pseudo, const RenderStyle* parentStyle) const
1331{
1332 if (pseudo < PseudoId::FirstInternalPseudoId && !style().hasPseudoStyle(pseudo))
1333 return nullptr;
1334
1335 RenderStyle* cachedStyle = style().getCachedPseudoStyle(pseudo);
1336 if (cachedStyle)
1337 return cachedStyle;
1338
1339 std::unique_ptr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
1340 if (result)
1341 return const_cast<RenderStyle&>(m_style).addCachedPseudoStyle(WTFMove(result));
1342 return nullptr;
1343}
1344
1345std::unique_ptr<RenderStyle> RenderElement::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, const RenderStyle* parentStyle, const RenderStyle* ownStyle) const
1346{
1347 if (pseudoStyleRequest.pseudoId < PseudoId::FirstInternalPseudoId && !ownStyle && !style().hasPseudoStyle(pseudoStyleRequest.pseudoId))
1348 return nullptr;
1349
1350 if (!parentStyle) {
1351 ASSERT(!ownStyle);
1352 parentStyle = &style();
1353 }
1354
1355 if (isAnonymous())
1356 return nullptr;
1357
1358 auto& styleResolver = element()->styleResolver();
1359
1360 std::unique_ptr<RenderStyle> style = styleResolver.pseudoStyleForElement(*element(), pseudoStyleRequest, *parentStyle);
1361
1362 if (style)
1363 Style::loadPendingResources(*style, document(), element());
1364
1365 return style;
1366}
1367
1368Color RenderElement::selectionColor(CSSPropertyID colorProperty) const
1369{
1370 // If the element is unselectable, or we are only painting the selection,
1371 // don't override the foreground color with the selection foreground color.
1372 if (style().userSelect() == UserSelect::None
1373 || (view().frameView().paintBehavior().containsAny({ PaintBehavior::SelectionOnly, PaintBehavior::SelectionAndBackgroundsOnly })))
1374 return Color();
1375
1376 if (std::unique_ptr<RenderStyle> pseudoStyle = selectionPseudoStyle()) {
1377 Color color = pseudoStyle->visitedDependentColorWithColorFilter(colorProperty);
1378 if (!color.isValid())
1379 color = pseudoStyle->visitedDependentColorWithColorFilter(CSSPropertyColor);
1380 return color;
1381 }
1382
1383 if (frame().selection().isFocusedAndActive())
1384 return theme().activeSelectionForegroundColor(styleColorOptions());
1385 return theme().inactiveSelectionForegroundColor(styleColorOptions());
1386}
1387
1388std::unique_ptr<RenderStyle> RenderElement::selectionPseudoStyle() const
1389{
1390 if (isAnonymous())
1391 return nullptr;
1392
1393 if (ShadowRoot* root = element()->containingShadowRoot()) {
1394 if (root->mode() == ShadowRootMode::UserAgent) {
1395 if (Element* shadowHost = element()->shadowHost())
1396 return shadowHost->renderer()->getUncachedPseudoStyle(PseudoStyleRequest(PseudoId::Selection));
1397 }
1398 }
1399
1400 return getUncachedPseudoStyle(PseudoStyleRequest(PseudoId::Selection));
1401}
1402
1403Color RenderElement::selectionForegroundColor() const
1404{
1405 return selectionColor(CSSPropertyWebkitTextFillColor);
1406}
1407
1408Color RenderElement::selectionEmphasisMarkColor() const
1409{
1410 return selectionColor(CSSPropertyWebkitTextEmphasisColor);
1411}
1412
1413Color RenderElement::selectionBackgroundColor() const
1414{
1415 if (style().userSelect() == UserSelect::None)
1416 return Color();
1417
1418 if (frame().selection().shouldShowBlockCursor() && frame().selection().isCaret())
1419 return theme().transformSelectionBackgroundColor(style().visitedDependentColorWithColorFilter(CSSPropertyColor), styleColorOptions());
1420
1421 std::unique_ptr<RenderStyle> pseudoStyle = selectionPseudoStyle();
1422 if (pseudoStyle && pseudoStyle->visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor).isValid())
1423 return theme().transformSelectionBackgroundColor(pseudoStyle->visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor), styleColorOptions());
1424
1425 if (frame().selection().isFocusedAndActive())
1426 return theme().activeSelectionBackgroundColor(styleColorOptions());
1427 return theme().inactiveSelectionBackgroundColor(styleColorOptions());
1428}
1429
1430bool RenderElement::getLeadingCorner(FloatPoint& point, bool& insideFixed) const
1431{
1432 if (!isInline() || isReplaced()) {
1433 point = localToAbsolute(FloatPoint(), UseTransforms, &insideFixed);
1434 return true;
1435 }
1436
1437 // find the next text/image child, to get a position
1438 const RenderObject* o = this;
1439 while (o) {
1440 const RenderObject* p = o;
1441 if (RenderObject* child = o->firstChildSlow())
1442 o = child;
1443 else if (o->nextSibling())
1444 o = o->nextSibling();
1445 else {
1446 RenderObject* next = 0;
1447 while (!next && o->parent()) {
1448 o = o->parent();
1449 next = o->nextSibling();
1450 }
1451 o = next;
1452
1453 if (!o)
1454 break;
1455 }
1456 ASSERT(o);
1457
1458 if (!o->isInline() || o->isReplaced()) {
1459 point = o->localToAbsolute(FloatPoint(), UseTransforms, &insideFixed);
1460 return true;
1461 }
1462
1463 if (p->node() && p->node() == element() && is<RenderText>(*o) && !downcast<RenderText>(*o).firstTextBox()) {
1464 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
1465 } else if (is<RenderText>(*o) || o->isReplaced()) {
1466 point = FloatPoint();
1467 if (is<RenderText>(*o) && downcast<RenderText>(*o).firstTextBox())
1468 point.move(downcast<RenderText>(*o).linesBoundingBox().x(), downcast<RenderText>(*o).topOfFirstText());
1469 else if (is<RenderBox>(*o))
1470 point.moveBy(downcast<RenderBox>(*o).location());
1471 point = o->container()->localToAbsolute(point, UseTransforms, &insideFixed);
1472 return true;
1473 }
1474 }
1475
1476 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
1477 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
1478 if (!o && document().view()) {
1479 point = FloatPoint(0, document().view()->contentsHeight());
1480 return true;
1481 }
1482 return false;
1483}
1484
1485bool RenderElement::getTrailingCorner(FloatPoint& point, bool& insideFixed) const
1486{
1487 if (!isInline() || isReplaced()) {
1488 point = localToAbsolute(LayoutPoint(downcast<RenderBox>(*this).size()), UseTransforms, &insideFixed);
1489 return true;
1490 }
1491
1492 // find the last text/image child, to get a position
1493 const RenderObject* o = this;
1494 while (o) {
1495 if (RenderObject* child = o->lastChildSlow())
1496 o = child;
1497 else if (o->previousSibling())
1498 o = o->previousSibling();
1499 else {
1500 RenderObject* prev = 0;
1501 while (!prev) {
1502 o = o->parent();
1503 if (!o)
1504 return false;
1505 prev = o->previousSibling();
1506 }
1507 o = prev;
1508 }
1509 ASSERT(o);
1510 if (is<RenderText>(*o) || o->isReplaced()) {
1511 point = FloatPoint();
1512 if (is<RenderText>(*o)) {
1513 LayoutRect linesBox = downcast<RenderText>(*o).linesBoundingBox();
1514 if (!linesBox.maxX() && !linesBox.maxY())
1515 continue;
1516 point.moveBy(linesBox.maxXMaxYCorner());
1517 } else
1518 point.moveBy(downcast<RenderBox>(*o).frameRect().maxXMaxYCorner());
1519 point = o->container()->localToAbsolute(point, UseTransforms, &insideFixed);
1520 return true;
1521 }
1522 }
1523 return true;
1524}
1525
1526LayoutRect RenderElement::absoluteAnchorRect(bool* insideFixed) const
1527{
1528 FloatPoint leading, trailing;
1529 bool leadingInFixed = false;
1530 bool trailingInFixed = false;
1531 getLeadingCorner(leading, leadingInFixed);
1532 getTrailingCorner(trailing, trailingInFixed);
1533
1534 FloatPoint upperLeft = leading;
1535 FloatPoint lowerRight = trailing;
1536
1537 // Vertical writing modes might mean the leading point is not in the top left
1538 if (!isInline() || isReplaced()) {
1539 upperLeft = FloatPoint(std::min(leading.x(), trailing.x()), std::min(leading.y(), trailing.y()));
1540 lowerRight = FloatPoint(std::max(leading.x(), trailing.x()), std::max(leading.y(), trailing.y()));
1541 } // Otherwise, it's not obvious what to do.
1542
1543 if (insideFixed) {
1544 // For now, just look at the leading corner. Handling one inside fixed and one not would be tricky.
1545 *insideFixed = leadingInFixed;
1546 }
1547
1548 return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
1549}
1550
1551const RenderElement* RenderElement::enclosingRendererWithTextDecoration(OptionSet<TextDecoration> textDecoration, bool firstLine) const
1552{
1553 const RenderElement* current = this;
1554 do {
1555 if (current->isRenderBlock())
1556 return current;
1557 if (!current->isRenderInline() || current->isRubyText())
1558 return nullptr;
1559
1560 const RenderStyle& styleToUse = firstLine ? current->firstLineStyle() : current->style();
1561 if (styleToUse.textDecoration() & textDecoration)
1562 return current;
1563 current = current->parent();
1564 } while (current && (!current->element() || (!is<HTMLAnchorElement>(*current->element()) && !current->element()->hasTagName(HTMLNames::fontTag))));
1565
1566 return current;
1567}
1568
1569void RenderElement::drawLineForBoxSide(GraphicsContext& graphicsContext, const FloatRect& rect, BoxSide side, Color color, BorderStyle borderStyle, float adjacentWidth1, float adjacentWidth2, bool antialias) const
1570{
1571 auto drawBorderRect = [&graphicsContext] (const FloatRect& rect)
1572 {
1573 if (rect.isEmpty())
1574 return;
1575 graphicsContext.drawRect(rect);
1576 };
1577
1578 auto drawLineFor = [this, &graphicsContext, color, antialias] (const FloatRect& rect, BoxSide side, BorderStyle borderStyle, const FloatSize& adjacent)
1579 {
1580 if (rect.isEmpty())
1581 return;
1582 drawLineForBoxSide(graphicsContext, rect, side, color, borderStyle, adjacent.width(), adjacent.height(), antialias);
1583 };
1584
1585 float x1 = rect.x();
1586 float x2 = rect.maxX();
1587 float y1 = rect.y();
1588 float y2 = rect.maxY();
1589 float thickness;
1590 float length;
1591 if (side == BSTop || side == BSBottom) {
1592 thickness = y2 - y1;
1593 length = x2 - x1;
1594 } else {
1595 thickness = x2 - x1;
1596 length = y2 - y1;
1597 }
1598 // FIXME: We really would like this check to be an ASSERT as we don't want to draw empty borders. However
1599 // nothing guarantees that the following recursive calls to drawLineForBoxSide will have non-null dimensions.
1600 if (!thickness || !length)
1601 return;
1602
1603 float deviceScaleFactor = document().deviceScaleFactor();
1604 if (borderStyle == BorderStyle::Double && (thickness * deviceScaleFactor) < 3)
1605 borderStyle = BorderStyle::Solid;
1606
1607 switch (borderStyle) {
1608 case BorderStyle::None:
1609 case BorderStyle::Hidden:
1610 return;
1611 case BorderStyle::Dotted:
1612 case BorderStyle::Dashed: {
1613 bool wasAntialiased = graphicsContext.shouldAntialias();
1614 StrokeStyle oldStrokeStyle = graphicsContext.strokeStyle();
1615 graphicsContext.setShouldAntialias(antialias);
1616 graphicsContext.setStrokeColor(color);
1617 graphicsContext.setStrokeThickness(thickness);
1618 graphicsContext.setStrokeStyle(borderStyle == BorderStyle::Dashed ? DashedStroke : DottedStroke);
1619 graphicsContext.drawLine(roundPointToDevicePixels(LayoutPoint(x1, y1), deviceScaleFactor), roundPointToDevicePixels(LayoutPoint(x2, y2), deviceScaleFactor));
1620 graphicsContext.setShouldAntialias(wasAntialiased);
1621 graphicsContext.setStrokeStyle(oldStrokeStyle);
1622 break;
1623 }
1624 case BorderStyle::Double: {
1625 float thirdOfThickness = ceilToDevicePixel(thickness / 3, deviceScaleFactor);
1626 ASSERT(thirdOfThickness);
1627
1628 if (!adjacentWidth1 && !adjacentWidth2) {
1629 StrokeStyle oldStrokeStyle = graphicsContext.strokeStyle();
1630 graphicsContext.setStrokeStyle(NoStroke);
1631 graphicsContext.setFillColor(color);
1632
1633 bool wasAntialiased = graphicsContext.shouldAntialias();
1634 graphicsContext.setShouldAntialias(antialias);
1635
1636 switch (side) {
1637 case BSTop:
1638 case BSBottom:
1639 drawBorderRect(snapRectToDevicePixels(x1, y1, length, thirdOfThickness, deviceScaleFactor));
1640 drawBorderRect(snapRectToDevicePixels(x1, y2 - thirdOfThickness, length, thirdOfThickness, deviceScaleFactor));
1641 break;
1642 case BSLeft:
1643 case BSRight:
1644 drawBorderRect(snapRectToDevicePixels(x1, y1, thirdOfThickness, length, deviceScaleFactor));
1645 drawBorderRect(snapRectToDevicePixels(x2 - thirdOfThickness, y1, thirdOfThickness, length, deviceScaleFactor));
1646 break;
1647 }
1648
1649 graphicsContext.setShouldAntialias(wasAntialiased);
1650 graphicsContext.setStrokeStyle(oldStrokeStyle);
1651 } else {
1652 float adjacent1BigThird = ceilToDevicePixel(adjacentWidth1 / 3, deviceScaleFactor);
1653 float adjacent2BigThird = ceilToDevicePixel(adjacentWidth2 / 3, deviceScaleFactor);
1654
1655 float offset1 = floorToDevicePixel(fabs(adjacentWidth1) * 2 / 3, deviceScaleFactor);
1656 float offset2 = floorToDevicePixel(fabs(adjacentWidth2) * 2 / 3, deviceScaleFactor);
1657
1658 float mitreOffset1 = adjacentWidth1 < 0 ? offset1 : 0;
1659 float mitreOffset2 = adjacentWidth1 > 0 ? offset1 : 0;
1660 float mitreOffset3 = adjacentWidth2 < 0 ? offset2 : 0;
1661 float mitreOffset4 = adjacentWidth2 > 0 ? offset2 : 0;
1662
1663 FloatRect paintBorderRect;
1664 switch (side) {
1665 case BSTop:
1666 paintBorderRect = snapRectToDevicePixels(LayoutRect(x1 + mitreOffset1, y1, (x2 - mitreOffset3) - (x1 + mitreOffset1), thirdOfThickness), deviceScaleFactor);
1667 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1668
1669 paintBorderRect = snapRectToDevicePixels(LayoutRect(x1 + mitreOffset2, y2 - thirdOfThickness, (x2 - mitreOffset4) - (x1 + mitreOffset2), thirdOfThickness), deviceScaleFactor);
1670 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1671 break;
1672 case BSLeft:
1673 paintBorderRect = snapRectToDevicePixels(LayoutRect(x1, y1 + mitreOffset1, thirdOfThickness, (y2 - mitreOffset3) - (y1 + mitreOffset1)), deviceScaleFactor);
1674 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1675
1676 paintBorderRect = snapRectToDevicePixels(LayoutRect(x2 - thirdOfThickness, y1 + mitreOffset2, thirdOfThickness, (y2 - mitreOffset4) - (y1 + mitreOffset2)), deviceScaleFactor);
1677 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1678 break;
1679 case BSBottom:
1680 paintBorderRect = snapRectToDevicePixels(LayoutRect(x1 + mitreOffset2, y1, (x2 - mitreOffset4) - (x1 + mitreOffset2), thirdOfThickness), deviceScaleFactor);
1681 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1682
1683 paintBorderRect = snapRectToDevicePixels(LayoutRect(x1 + mitreOffset1, y2 - thirdOfThickness, (x2 - mitreOffset3) - (x1 + mitreOffset1), thirdOfThickness), deviceScaleFactor);
1684 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1685 break;
1686 case BSRight:
1687 paintBorderRect = snapRectToDevicePixels(LayoutRect(x1, y1 + mitreOffset2, thirdOfThickness, (y2 - mitreOffset4) - (y1 + mitreOffset2)), deviceScaleFactor);
1688 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1689
1690 paintBorderRect = snapRectToDevicePixels(LayoutRect(x2 - thirdOfThickness, y1 + mitreOffset1, thirdOfThickness, (y2 - mitreOffset3) - (y1 + mitreOffset1)), deviceScaleFactor);
1691 drawLineFor(paintBorderRect, side, BorderStyle::Solid, FloatSize(adjacent1BigThird, adjacent2BigThird));
1692 break;
1693 default:
1694 break;
1695 }
1696 }
1697 break;
1698 }
1699 case BorderStyle::Ridge:
1700 case BorderStyle::Groove: {
1701 BorderStyle s1;
1702 BorderStyle s2;
1703 if (borderStyle == BorderStyle::Groove) {
1704 s1 = BorderStyle::Inset;
1705 s2 = BorderStyle::Outset;
1706 } else {
1707 s1 = BorderStyle::Outset;
1708 s2 = BorderStyle::Inset;
1709 }
1710
1711 float adjacent1BigHalf = ceilToDevicePixel(adjacentWidth1 / 2, deviceScaleFactor);
1712 float adjacent2BigHalf = ceilToDevicePixel(adjacentWidth2 / 2, deviceScaleFactor);
1713
1714 float adjacent1SmallHalf = floorToDevicePixel(adjacentWidth1 / 2, deviceScaleFactor);
1715 float adjacent2SmallHalf = floorToDevicePixel(adjacentWidth2 / 2, deviceScaleFactor);
1716
1717 float offset1 = 0;
1718 float offset2 = 0;
1719 float offset3 = 0;
1720 float offset4 = 0;
1721
1722 if (((side == BSTop || side == BSLeft) && adjacentWidth1 < 0) || ((side == BSBottom || side == BSRight) && adjacentWidth1 > 0))
1723 offset1 = floorToDevicePixel(adjacentWidth1 / 2, deviceScaleFactor);
1724
1725 if (((side == BSTop || side == BSLeft) && adjacentWidth2 < 0) || ((side == BSBottom || side == BSRight) && adjacentWidth2 > 0))
1726 offset2 = ceilToDevicePixel(adjacentWidth2 / 2, deviceScaleFactor);
1727
1728 if (((side == BSTop || side == BSLeft) && adjacentWidth1 > 0) || ((side == BSBottom || side == BSRight) && adjacentWidth1 < 0))
1729 offset3 = floorToDevicePixel(fabs(adjacentWidth1) / 2, deviceScaleFactor);
1730
1731 if (((side == BSTop || side == BSLeft) && adjacentWidth2 > 0) || ((side == BSBottom || side == BSRight) && adjacentWidth2 < 0))
1732 offset4 = ceilToDevicePixel(adjacentWidth2 / 2, deviceScaleFactor);
1733
1734 float adjustedX = ceilToDevicePixel((x1 + x2) / 2, deviceScaleFactor);
1735 float adjustedY = ceilToDevicePixel((y1 + y2) / 2, deviceScaleFactor);
1736 // Quads can't use the default snapping rect functions.
1737 x1 = roundToDevicePixel(x1, deviceScaleFactor);
1738 x2 = roundToDevicePixel(x2, deviceScaleFactor);
1739 y1 = roundToDevicePixel(y1, deviceScaleFactor);
1740 y2 = roundToDevicePixel(y2, deviceScaleFactor);
1741
1742 switch (side) {
1743 case BSTop:
1744 drawLineFor(FloatRect(FloatPoint(x1 + offset1, y1), FloatPoint(x2 - offset2, adjustedY)), side, s1, FloatSize(adjacent1BigHalf, adjacent2BigHalf));
1745 drawLineFor(FloatRect(FloatPoint(x1 + offset3, adjustedY), FloatPoint(x2 - offset4, y2)), side, s2, FloatSize(adjacent1SmallHalf, adjacent2SmallHalf));
1746 break;
1747 case BSLeft:
1748 drawLineFor(FloatRect(FloatPoint(x1, y1 + offset1), FloatPoint(adjustedX, y2 - offset2)), side, s1, FloatSize(adjacent1BigHalf, adjacent2BigHalf));
1749 drawLineFor(FloatRect(FloatPoint(adjustedX, y1 + offset3), FloatPoint(x2, y2 - offset4)), side, s2, FloatSize(adjacent1SmallHalf, adjacent2SmallHalf));
1750 break;
1751 case BSBottom:
1752 drawLineFor(FloatRect(FloatPoint(x1 + offset1, y1), FloatPoint(x2 - offset2, adjustedY)), side, s2, FloatSize(adjacent1BigHalf, adjacent2BigHalf));
1753 drawLineFor(FloatRect(FloatPoint(x1 + offset3, adjustedY), FloatPoint(x2 - offset4, y2)), side, s1, FloatSize(adjacent1SmallHalf, adjacent2SmallHalf));
1754 break;
1755 case BSRight:
1756 drawLineFor(FloatRect(FloatPoint(x1, y1 + offset1), FloatPoint(adjustedX, y2 - offset2)), side, s2, FloatSize(adjacent1BigHalf, adjacent2BigHalf));
1757 drawLineFor(FloatRect(FloatPoint(adjustedX, y1 + offset3), FloatPoint(x2, y2 - offset4)), side, s1, FloatSize(adjacent1SmallHalf, adjacent2SmallHalf));
1758 break;
1759 }
1760 break;
1761 }
1762 case BorderStyle::Inset:
1763 case BorderStyle::Outset:
1764 calculateBorderStyleColor(borderStyle, side, color);
1765 FALLTHROUGH;
1766 case BorderStyle::Solid: {
1767 StrokeStyle oldStrokeStyle = graphicsContext.strokeStyle();
1768 ASSERT(x2 >= x1);
1769 ASSERT(y2 >= y1);
1770 if (!adjacentWidth1 && !adjacentWidth2) {
1771 graphicsContext.setStrokeStyle(NoStroke);
1772 graphicsContext.setFillColor(color);
1773 bool wasAntialiased = graphicsContext.shouldAntialias();
1774 graphicsContext.setShouldAntialias(antialias);
1775 drawBorderRect(snapRectToDevicePixels(x1, y1, x2 - x1, y2 - y1, deviceScaleFactor));
1776 graphicsContext.setShouldAntialias(wasAntialiased);
1777 graphicsContext.setStrokeStyle(oldStrokeStyle);
1778 return;
1779 }
1780
1781 // FIXME: These roundings should be replaced by ASSERT(device pixel positioned) when all the callers have transitioned to device pixels.
1782 x1 = roundToDevicePixel(x1, deviceScaleFactor);
1783 y1 = roundToDevicePixel(y1, deviceScaleFactor);
1784 x2 = roundToDevicePixel(x2, deviceScaleFactor);
1785 y2 = roundToDevicePixel(y2, deviceScaleFactor);
1786
1787 Vector<FloatPoint> quad;
1788 quad.reserveInitialCapacity(4);
1789 switch (side) {
1790 case BSTop:
1791 quad.uncheckedAppend({ x1 + std::max<float>(-adjacentWidth1, 0), y1 });
1792 quad.uncheckedAppend({ x1 + std::max<float>( adjacentWidth1, 0), y2 });
1793 quad.uncheckedAppend({ x2 - std::max<float>( adjacentWidth2, 0), y2 });
1794 quad.uncheckedAppend({ x2 - std::max<float>(-adjacentWidth2, 0), y1 });
1795 break;
1796 case BSBottom:
1797 quad.uncheckedAppend({ x1 + std::max<float>( adjacentWidth1, 0), y1 });
1798 quad.uncheckedAppend({ x1 + std::max<float>(-adjacentWidth1, 0), y2 });
1799 quad.uncheckedAppend({ x2 - std::max<float>(-adjacentWidth2, 0), y2 });
1800 quad.uncheckedAppend({ x2 - std::max<float>( adjacentWidth2, 0), y1 });
1801 break;
1802 case BSLeft:
1803 quad.uncheckedAppend({ x1, y1 + std::max<float>(-adjacentWidth1, 0) });
1804 quad.uncheckedAppend({ x1, y2 - std::max<float>(-adjacentWidth2, 0) });
1805 quad.uncheckedAppend({ x2, y2 - std::max<float>( adjacentWidth2, 0) });
1806 quad.uncheckedAppend({ x2, y1 + std::max<float>( adjacentWidth1, 0) });
1807 break;
1808 case BSRight:
1809 quad.uncheckedAppend({ x1, y1 + std::max<float>( adjacentWidth1, 0) });
1810 quad.uncheckedAppend({ x1, y2 - std::max<float>( adjacentWidth2, 0) });
1811 quad.uncheckedAppend({ x2, y2 - std::max<float>(-adjacentWidth2, 0) });
1812 quad.uncheckedAppend({ x2, y1 + std::max<float>(-adjacentWidth1, 0) });
1813 break;
1814 }
1815
1816 graphicsContext.setStrokeStyle(NoStroke);
1817 graphicsContext.setFillColor(color);
1818 bool wasAntialiased = graphicsContext.shouldAntialias();
1819 graphicsContext.setShouldAntialias(antialias);
1820 graphicsContext.fillPath(Path::polygonPathFromPoints(quad));
1821 graphicsContext.setShouldAntialias(wasAntialiased);
1822
1823 graphicsContext.setStrokeStyle(oldStrokeStyle);
1824 break;
1825 }
1826 }
1827}
1828
1829static bool usePlatformFocusRingColorForOutlineStyleAuto()
1830{
1831#if PLATFORM(COCOA)
1832 return true;
1833#else
1834 return false;
1835#endif
1836}
1837
1838static bool useShrinkWrappedFocusRingForOutlineStyleAuto()
1839{
1840#if PLATFORM(COCOA)
1841 return true;
1842#else
1843 return false;
1844#endif
1845}
1846
1847static bool drawFocusRing(GraphicsContext& context, Page& page, const Path& path, const RenderStyle& style, Color focusRingColor)
1848{
1849 bool needsRepaint = false;
1850#if PLATFORM(MAC)
1851 context.drawFocusRing(path, page.focusController().timeSinceFocusWasSet().seconds(), needsRepaint, focusRingColor);
1852 UNUSED_PARAM(style);
1853#else
1854 context.drawFocusRing(path, style.outlineWidth(), style.outlineOffset(), focusRingColor);
1855 UNUSED_PARAM(page);
1856#endif
1857 return needsRepaint;
1858}
1859
1860static bool drawFocusRing(GraphicsContext& context, Page& page, Vector<FloatRect> rects, const RenderStyle& style, Color focusRingColor)
1861{
1862 bool needsRepaint = false;
1863#if PLATFORM(MAC)
1864 context.drawFocusRing(rects, page.focusController().timeSinceFocusWasSet().seconds(), needsRepaint, focusRingColor);
1865 UNUSED_PARAM(style);
1866#else
1867 context.drawFocusRing(rects, style.outlineWidth(), style.outlineOffset(), focusRingColor);
1868 UNUSED_PARAM(page);
1869#endif
1870 return needsRepaint;
1871}
1872
1873
1874void RenderElement::paintFocusRing(PaintInfo& paintInfo, const RenderStyle& style, const Vector<LayoutRect>& focusRingRects)
1875{
1876 ASSERT(style.outlineStyleIsAuto() == OutlineIsAuto::On);
1877 float outlineOffset = style.outlineOffset();
1878 Vector<FloatRect> pixelSnappedFocusRingRects;
1879 float deviceScaleFactor = document().deviceScaleFactor();
1880 for (auto rect : focusRingRects) {
1881 rect.inflate(outlineOffset);
1882 pixelSnappedFocusRingRects.append(snapRectToDevicePixels(rect, deviceScaleFactor));
1883 }
1884 Color focusRingColor = usePlatformFocusRingColorForOutlineStyleAuto() ? RenderTheme::singleton().focusRingColor(styleColorOptions()) : style.visitedDependentColorWithColorFilter(CSSPropertyOutlineColor);
1885 bool needsRepaint;
1886 if (useShrinkWrappedFocusRingForOutlineStyleAuto() && style.hasBorderRadius()) {
1887 Path path = PathUtilities::pathWithShrinkWrappedRectsForOutline(pixelSnappedFocusRingRects, style.border(), outlineOffset, style.direction(), style.writingMode(),
1888 document().deviceScaleFactor());
1889 if (path.isEmpty()) {
1890 for (auto rect : pixelSnappedFocusRingRects)
1891 path.addRect(rect);
1892 }
1893 needsRepaint = drawFocusRing(paintInfo.context(), page(), path, style, focusRingColor);
1894 } else
1895 needsRepaint = drawFocusRing(paintInfo.context(), page(), pixelSnappedFocusRingRects, style, focusRingColor);
1896 if (needsRepaint)
1897 page().focusController().setFocusedElementNeedsRepaint();
1898}
1899
1900void RenderElement::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
1901{
1902 GraphicsContext& graphicsContext = paintInfo.context();
1903 if (graphicsContext.paintingDisabled())
1904 return;
1905
1906 if (!hasOutline())
1907 return;
1908
1909 auto& styleToUse = style();
1910 float outlineWidth = floorToDevicePixel(styleToUse.outlineWidth(), document().deviceScaleFactor());
1911 float outlineOffset = floorToDevicePixel(styleToUse.outlineOffset(), document().deviceScaleFactor());
1912
1913 // Only paint the focus ring by hand if the theme isn't able to draw it.
1914 if (styleToUse.outlineStyleIsAuto() == OutlineIsAuto::On && !theme().supportsFocusRing(styleToUse)) {
1915 Vector<LayoutRect> focusRingRects;
1916 LayoutRect paintRectToUse { paintRect };
1917#if PLATFORM(IOS_FAMILY)
1918 // Workaround for <rdar://problem/6209763>. Force the painting bounds of checkboxes and radio controls to be square.
1919 // FIXME: Consolidate this code with the same code in RenderBox::paintBoxDecorations(). See <https://bugs.webkit.org/show_bug.cgi?id=194781>.
1920 if (style().appearance() == CheckboxPart || style().appearance() == RadioPart) {
1921 int width = std::min(paintRect.width(), paintRect.height());
1922 int height = width;
1923 paintRectToUse = IntRect { paintRect.x(), paintRect.y() + (downcast<RenderBox>(*this).height() - height) / 2, width, height }; // Vertically center the checkbox, like on desktop
1924 }
1925#endif
1926 addFocusRingRects(focusRingRects, paintRectToUse.location(), paintInfo.paintContainer);
1927 paintFocusRing(paintInfo, styleToUse, focusRingRects);
1928 }
1929
1930 if (hasOutlineAnnotation() && styleToUse.outlineStyleIsAuto() == OutlineIsAuto::Off && !theme().supportsFocusRing(styleToUse))
1931 addPDFURLRect(paintInfo, paintRect.location());
1932
1933 if (styleToUse.outlineStyleIsAuto() == OutlineIsAuto::On || styleToUse.outlineStyle() == BorderStyle::None)
1934 return;
1935
1936 FloatRect outer = paintRect;
1937 outer.inflate(outlineOffset + outlineWidth);
1938 FloatRect inner = outer;
1939 inner.inflate(-outlineWidth);
1940
1941 // FIXME: This prevents outlines from painting inside the object. See bug 12042
1942 if (outer.isEmpty())
1943 return;
1944
1945 BorderStyle outlineStyle = styleToUse.outlineStyle();
1946 Color outlineColor = styleToUse.visitedDependentColorWithColorFilter(CSSPropertyOutlineColor);
1947
1948 bool useTransparencyLayer = !outlineColor.isOpaque();
1949 if (useTransparencyLayer) {
1950 if (outlineStyle == BorderStyle::Solid) {
1951 Path path;
1952 path.addRect(outer);
1953 path.addRect(inner);
1954 graphicsContext.setFillRule(WindRule::EvenOdd);
1955 graphicsContext.setFillColor(outlineColor);
1956 graphicsContext.fillPath(path);
1957 return;
1958 }
1959 graphicsContext.beginTransparencyLayer(outlineColor.alphaAsFloat());
1960 outlineColor = outlineColor.opaqueColor();
1961 }
1962
1963 float leftOuter = outer.x();
1964 float leftInner = inner.x();
1965 float rightOuter = outer.maxX();
1966 float rightInner = std::min(inner.maxX(), rightOuter);
1967 float topOuter = outer.y();
1968 float topInner = inner.y();
1969 float bottomOuter = outer.maxY();
1970 float bottomInner = std::min(inner.maxY(), bottomOuter);
1971
1972 drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(leftOuter, topOuter), FloatPoint(leftInner, bottomOuter)), BSLeft, outlineColor, outlineStyle, outlineWidth, outlineWidth);
1973 drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(leftOuter, topOuter), FloatPoint(rightOuter, topInner)), BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth);
1974 drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(rightInner, topOuter), FloatPoint(rightOuter, bottomOuter)), BSRight, outlineColor, outlineStyle, outlineWidth, outlineWidth);
1975 drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(leftOuter, bottomInner), FloatPoint(rightOuter, bottomOuter)), BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth);
1976
1977 if (useTransparencyLayer)
1978 graphicsContext.endTransparencyLayer();
1979}
1980
1981void RenderElement::issueRepaintForOutlineAuto(float outlineSize)
1982{
1983 LayoutRect repaintRect;
1984 Vector<LayoutRect> focusRingRects;
1985 addFocusRingRects(focusRingRects, LayoutPoint(), containerForRepaint());
1986 for (auto rect : focusRingRects) {
1987 rect.inflate(outlineSize);
1988 repaintRect.unite(rect);
1989 }
1990 repaintRectangle(repaintRect);
1991}
1992
1993void RenderElement::updateOutlineAutoAncestor(bool hasOutlineAuto)
1994{
1995 for (auto& child : childrenOfType<RenderObject>(*this)) {
1996 if (hasOutlineAuto == child.hasOutlineAutoAncestor())
1997 continue;
1998 child.setHasOutlineAutoAncestor(hasOutlineAuto);
1999 bool childHasOutlineAuto = child.outlineStyleForRepaint().outlineStyleIsAuto() == OutlineIsAuto::On;
2000 if (childHasOutlineAuto)
2001 continue;
2002 if (!is<RenderElement>(child))
2003 continue;
2004 downcast<RenderElement>(child).updateOutlineAutoAncestor(hasOutlineAuto);
2005 }
2006 if (is<RenderBoxModelObject>(*this)) {
2007 if (auto* continuation = downcast<RenderBoxModelObject>(*this).continuation())
2008 continuation->updateOutlineAutoAncestor(hasOutlineAuto);
2009 }
2010}
2011
2012bool RenderElement::hasOutlineAnnotation() const
2013{
2014 return element() && element()->isLink() && document().printing();
2015}
2016
2017bool RenderElement::hasSelfPaintingLayer() const
2018{
2019 if (!hasLayer())
2020 return false;
2021 auto& layerModelObject = downcast<RenderLayerModelObject>(*this);
2022 return layerModelObject.hasSelfPaintingLayer();
2023}
2024
2025bool RenderElement::checkForRepaintDuringLayout() const
2026{
2027 if (document().view()->layoutContext().needsFullRepaint() || !everHadLayout() || hasSelfPaintingLayer())
2028 return false;
2029 return !settings().repaintOutsideLayoutEnabled();
2030}
2031
2032RespectImageOrientationEnum RenderElement::shouldRespectImageOrientation() const
2033{
2034#if USE(CG) || USE(CAIRO)
2035 // This can only be enabled for ports which honor the orientation flag in their drawing code.
2036 if (document().isImageDocument())
2037 return RespectImageOrientation;
2038#endif
2039 // Respect the image's orientation if it's being used as a full-page image or it's
2040 // an <img> and the setting to respect it everywhere is set.
2041 return settings().shouldRespectImageOrientation() && is<HTMLImageElement>(element()) ? RespectImageOrientation : DoNotRespectImageOrientation;
2042}
2043
2044void RenderElement::adjustFragmentedFlowStateOnContainingBlockChangeIfNeeded()
2045{
2046 if (fragmentedFlowState() == NotInsideFragmentedFlow)
2047 return;
2048
2049 // Invalidate the containing block caches.
2050 if (is<RenderBlock>(*this))
2051 downcast<RenderBlock>(*this).resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants();
2052
2053 // Adjust the flow tread state on the subtree.
2054 setFragmentedFlowState(RenderObject::computedFragmentedFlowState(*this));
2055 for (auto& descendant : descendantsOfType<RenderObject>(*this))
2056 descendant.setFragmentedFlowState(RenderObject::computedFragmentedFlowState(descendant));
2057}
2058
2059void RenderElement::removeFromRenderFragmentedFlow()
2060{
2061 ASSERT(fragmentedFlowState() != NotInsideFragmentedFlow);
2062 // Sometimes we remove the element from the flow, but it's not destroyed at that time.
2063 // It's only until later when we actually destroy it and remove all the children from it.
2064 // Currently, that happens for firstLetter elements and list markers.
2065 // Pass in the flow thread so that we don't have to look it up for all the children.
2066 removeFromRenderFragmentedFlowIncludingDescendants(true);
2067}
2068
2069void RenderElement::removeFromRenderFragmentedFlowIncludingDescendants(bool shouldUpdateState)
2070{
2071 // Once we reach another flow thread we don't need to update the flow thread state
2072 // but we have to continue cleanup the flow thread info.
2073 if (isRenderFragmentedFlow())
2074 shouldUpdateState = false;
2075
2076 for (auto& child : childrenOfType<RenderObject>(*this)) {
2077 if (is<RenderElement>(child)) {
2078 downcast<RenderElement>(child).removeFromRenderFragmentedFlowIncludingDescendants(shouldUpdateState);
2079 continue;
2080 }
2081 if (shouldUpdateState)
2082 child.setFragmentedFlowState(NotInsideFragmentedFlow);
2083 }
2084
2085 // We have to ask for our containing flow thread as it may be above the removed sub-tree.
2086 RenderFragmentedFlow* enclosingFragmentedFlow = this->enclosingFragmentedFlow();
2087 while (enclosingFragmentedFlow) {
2088 enclosingFragmentedFlow->removeFlowChildInfo(*this);
2089
2090 if (enclosingFragmentedFlow->fragmentedFlowState() == NotInsideFragmentedFlow)
2091 break;
2092 auto* parent = enclosingFragmentedFlow->parent();
2093 if (!parent)
2094 break;
2095 enclosingFragmentedFlow = parent->enclosingFragmentedFlow();
2096 }
2097 if (is<RenderBlock>(*this))
2098 downcast<RenderBlock>(*this).setCachedEnclosingFragmentedFlowNeedsUpdate();
2099
2100 if (shouldUpdateState)
2101 setFragmentedFlowState(NotInsideFragmentedFlow);
2102}
2103
2104void RenderElement::resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants(RenderFragmentedFlow* fragmentedFlow)
2105{
2106 if (fragmentedFlow)
2107 fragmentedFlow->removeFlowChildInfo(*this);
2108
2109 for (auto& child : childrenOfType<RenderElement>(*this))
2110 child.resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants(fragmentedFlow);
2111}
2112
2113#if ENABLE(TEXT_AUTOSIZING)
2114static RenderObject::BlockContentHeightType includeNonFixedHeight(const RenderObject& renderer)
2115{
2116 const RenderStyle& style = renderer.style();
2117 if (style.height().type() == Fixed) {
2118 if (is<RenderBlock>(renderer)) {
2119 // For fixed height styles, if the overflow size of the element spills out of the specified
2120 // height, assume we can apply text auto-sizing.
2121 if (style.overflowY() == Overflow::Visible
2122 && style.height().value() < downcast<RenderBlock>(renderer).layoutOverflowRect().maxY())
2123 return RenderObject::OverflowHeight;
2124 }
2125 return RenderObject::FixedHeight;
2126 }
2127 if (renderer.document().settings().textAutosizingUsesIdempotentMode() && style.maxHeight().type() == Fixed && is<RenderBlock>(renderer) && style.maxHeight().value() <= downcast<RenderBlock>(renderer).layoutOverflowRect().maxY())
2128 return RenderObject::FixedHeight;
2129 return RenderObject::FlexibleHeight;
2130}
2131
2132void RenderElement::adjustComputedFontSizesOnBlocks(float size, float visibleWidth)
2133{
2134 Document* document = view().frameView().frame().document();
2135 if (!document)
2136 return;
2137
2138 auto pageScale = document->page() ? document->page()->initialScale() : 1.0f;
2139
2140 Vector<int> depthStack;
2141 int currentDepth = 0;
2142 int newFixedDepth = 0;
2143 auto idempotentMode = document->settings().textAutosizingUsesIdempotentMode();
2144
2145 // We don't apply autosizing to nodes with fixed height normally.
2146 // But we apply it to nodes which are located deep enough
2147 // (nesting depth is greater than some const) inside of a parent block
2148 // which has fixed height but its content overflows intentionally.
2149 for (RenderObject* descendent = traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth); descendent; descendent = descendent->traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth)) {
2150 while (depthStack.size() > 0 && currentDepth <= depthStack[depthStack.size() - 1])
2151 depthStack.remove(depthStack.size() - 1);
2152 if (newFixedDepth)
2153 depthStack.append(newFixedDepth);
2154
2155 int stackSize = depthStack.size();
2156 if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
2157 downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth, pageScale, idempotentMode);
2158 newFixedDepth = 0;
2159 }
2160
2161 // Remove style from auto-sizing table that are no longer valid.
2162 document->textAutoSizing().updateRenderTree();
2163}
2164
2165void RenderElement::resetTextAutosizing()
2166{
2167 Document* document = view().frameView().frame().document();
2168 if (!document)
2169 return;
2170
2171 LOG(TextAutosizing, "RenderElement::resetTextAutosizing()");
2172
2173 document->textAutoSizing().reset();
2174
2175 Vector<int> depthStack;
2176 int currentDepth = 0;
2177 int newFixedDepth = 0;
2178 auto idempotentMode = document->settings().textAutosizingUsesIdempotentMode();
2179
2180 for (RenderObject* descendent = traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth); descendent; descendent = descendent->traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth)) {
2181 while (depthStack.size() > 0 && currentDepth <= depthStack[depthStack.size() - 1])
2182 depthStack.remove(depthStack.size() - 1);
2183 if (newFixedDepth)
2184 depthStack.append(newFixedDepth);
2185
2186 int stackSize = depthStack.size();
2187 if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
2188 downcast<RenderBlockFlow>(*descendent).resetComputedFontSize();
2189 newFixedDepth = 0;
2190 }
2191}
2192#endif // ENABLE(TEXT_AUTOSIZING)
2193
2194}
2195