Introduce RenderTreeBuilder
[WebKit-https.git] / Source / WebCore / style / RenderTreeUpdater.cpp
1 /*
2  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RenderTreeUpdater.h"
28
29 #include "AXObjectCache.h"
30 #include "CSSAnimationController.h"
31 #include "ComposedTreeAncestorIterator.h"
32 #include "ComposedTreeIterator.h"
33 #include "Document.h"
34 #include "Element.h"
35 #include "HTMLParserIdioms.h"
36 #include "HTMLSlotElement.h"
37 #include "InspectorInstrumentation.h"
38 #include "NodeRenderStyle.h"
39 #include "PseudoElement.h"
40 #include "RenderDescendantIterator.h"
41 #include "RenderFullScreen.h"
42 #include "RenderInline.h"
43 #include "RenderListItem.h"
44 #include "RenderTreeUpdaterFirstLetter.h"
45 #include "RenderTreeUpdaterGeneratedContent.h"
46 #include "RenderTreeUpdaterListItem.h"
47 #include "RenderTreeUpdaterMultiColumn.h"
48 #include "StyleResolver.h"
49 #include "StyleTreeResolver.h"
50 #include <wtf/SystemTracing.h>
51
52 #if PLATFORM(IOS)
53 #include "WKContentObservation.h"
54 #include "WKContentObservationInternal.h"
55 #endif
56
57 namespace WebCore {
58
59 #if PLATFORM(IOS)
60 class CheckForVisibilityChange {
61 public:
62     CheckForVisibilityChange(const Element&);
63     ~CheckForVisibilityChange();
64
65 private:
66     const Element& m_element;
67     EDisplay m_previousDisplay;
68     EVisibility m_previousVisibility;
69     EVisibility m_previousImplicitVisibility;
70 };
71 #endif // PLATFORM(IOS)
72
73 RenderTreeUpdater::Parent::Parent(ContainerNode& root)
74     : element(is<Document>(root) ? nullptr : downcast<Element>(&root))
75     , renderTreePosition(RenderTreePosition(*root.renderer()))
76 {
77 }
78
79 RenderTreeUpdater::Parent::Parent(Element& element, const Style::ElementUpdates* updates)
80     : element(&element)
81     , updates(updates)
82     , renderTreePosition(element.renderer() ? std::make_optional(RenderTreePosition(*element.renderer())) : std::nullopt)
83 {
84 }
85
86 RenderTreeUpdater::RenderTreeUpdater(Document& document)
87     : m_document(document)
88     , m_generatedContent(std::make_unique<GeneratedContent>(*this))
89 {
90 }
91
92 RenderTreeUpdater::~RenderTreeUpdater() = default;
93
94 static ContainerNode* findRenderingRoot(ContainerNode& node)
95 {
96     if (node.renderer())
97         return &node;
98     for (auto& ancestor : composedTreeAncestors(node)) {
99         if (ancestor.renderer())
100             return &ancestor;
101         if (!ancestor.hasDisplayContents())
102             return nullptr;
103     }
104     return &node.document();
105 }
106
107 static ListHashSet<ContainerNode*> findRenderingRoots(const Style::Update& update)
108 {
109     ListHashSet<ContainerNode*> renderingRoots;
110     for (auto* root : update.roots()) {
111         auto* renderingRoot = findRenderingRoot(*root);
112         if (!renderingRoot)
113             continue;
114         renderingRoots.add(renderingRoot);
115     }
116     return renderingRoots;
117 }
118
119 void RenderTreeUpdater::commit(std::unique_ptr<const Style::Update> styleUpdate)
120 {
121     ASSERT(&m_document == &styleUpdate->document());
122
123     if (!m_document.shouldCreateRenderers() || !m_document.renderView())
124         return;
125     
126     TraceScope scope(RenderTreeBuildStart, RenderTreeBuildEnd);
127
128     Style::PostResolutionCallbackDisabler callbackDisabler(m_document);
129
130     m_styleUpdate = WTFMove(styleUpdate);
131
132     for (auto* root : findRenderingRoots(*m_styleUpdate))
133         updateRenderTree(*root);
134
135     generatedContent().updateRemainingQuotes();
136
137     MultiColumn::update(renderView());
138
139     m_styleUpdate = nullptr;
140 }
141
142 static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
143 {
144     if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
145         return false;
146     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
147         return false;
148     return true;
149 }
150
151 void RenderTreeUpdater::updateRenderTree(ContainerNode& root)
152 {
153     ASSERT(root.renderer());
154     ASSERT(m_parentStack.isEmpty());
155
156     m_parentStack.append(Parent(root));
157
158     auto descendants = composedTreeDescendants(root);
159     auto it = descendants.begin();
160     auto end = descendants.end();
161
162     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156172
163     it.dropAssertions();
164
165     while (it != end) {
166         popParentsToDepth(it.depth());
167
168         auto& node = *it;
169
170         if (auto* renderer = node.renderer())
171             renderTreePosition().invalidateNextSibling(*renderer);
172         else if (is<Element>(node) && downcast<Element>(node).hasDisplayContents())
173             renderTreePosition().invalidateNextSibling();
174
175         if (is<Text>(node)) {
176             auto& text = downcast<Text>(node);
177             auto* textUpdate = m_styleUpdate->textUpdate(text);
178             bool didCreateParent = parent().updates && parent().updates->update.change == Style::Detach;
179             bool mayNeedUpdateWhitespaceOnlyRenderer = renderingParent().didCreateOrDestroyChildRenderer && text.data().isAllSpecialCharacters<isHTMLSpace>();
180             if (didCreateParent || textUpdate || mayNeedUpdateWhitespaceOnlyRenderer)
181                 updateTextRenderer(text, textUpdate);
182
183             storePreviousRenderer(text);
184             it.traverseNextSkippingChildren();
185             continue;
186         }
187
188         auto& element = downcast<Element>(node);
189
190         auto* elementUpdates = m_styleUpdate->elementUpdates(element);
191
192         // We hop through display: contents elements in findRenderingRoot, so
193         // there may be other updates down the tree.
194         if (!elementUpdates && !element.hasDisplayContents()) {
195             storePreviousRenderer(element);
196             it.traverseNextSkippingChildren();
197             continue;
198         }
199
200         if (elementUpdates)
201             updateElementRenderer(element, elementUpdates->update);
202
203         storePreviousRenderer(element);
204
205         bool mayHaveRenderedDescendants = element.renderer() || (element.hasDisplayContents() && shouldCreateRenderer(element, renderTreePosition().parent()));
206         if (!mayHaveRenderedDescendants) {
207             it.traverseNextSkippingChildren();
208             continue;
209         }
210
211         pushParent(element, elementUpdates);
212
213         it.traverseNext();
214     }
215
216     popParentsToDepth(0);
217 }
218
219 auto RenderTreeUpdater::renderingParent() -> Parent&
220 {
221     for (unsigned i = m_parentStack.size(); i--;) {
222         if (m_parentStack[i].renderTreePosition)
223             return m_parentStack[i];
224     }
225     ASSERT_NOT_REACHED();
226     return m_parentStack.last();
227 }
228
229 RenderTreePosition& RenderTreeUpdater::renderTreePosition()
230 {
231     return *renderingParent().renderTreePosition;
232 }
233
234 void RenderTreeUpdater::pushParent(Element& element, const Style::ElementUpdates* updates)
235 {
236     m_parentStack.append(Parent(element, updates));
237
238     updateBeforeDescendants(element, updates);
239 }
240
241 void RenderTreeUpdater::popParent()
242 {
243     auto& parent = m_parentStack.last();
244     if (parent.element)
245         updateAfterDescendants(*parent.element, parent.updates);
246
247     m_parentStack.removeLast();
248 }
249
250 void RenderTreeUpdater::popParentsToDepth(unsigned depth)
251 {
252     ASSERT(m_parentStack.size() >= depth);
253
254     while (m_parentStack.size() > depth)
255         popParent();
256 }
257
258 void RenderTreeUpdater::updateBeforeDescendants(Element& element, const Style::ElementUpdates* updates)
259 {
260     if (updates)
261         generatedContent().updatePseudoElement(element, updates->beforePseudoElementUpdate, BEFORE);
262 }
263
264 void RenderTreeUpdater::updateAfterDescendants(Element& element, const Style::ElementUpdates* updates)
265 {
266     if (updates)
267         generatedContent().updatePseudoElement(element, updates->afterPseudoElementUpdate, AFTER);
268
269     auto* renderer = element.renderer();
270     if (!renderer)
271         return;
272
273     // These functions do render tree mutations that require descendant renderers.
274     if (is<RenderBlock>(*renderer))
275         FirstLetter::update(downcast<RenderBlock>(*renderer));
276     if (is<RenderListItem>(*renderer))
277         ListItem::updateMarker(m_builder, downcast<RenderListItem>(*renderer));
278     if (is<RenderBlockFlow>(*renderer))
279         MultiColumn::update(downcast<RenderBlockFlow>(*renderer));
280
281     if (element.hasCustomStyleResolveCallbacks() && updates && updates->update.change == Style::Detach)
282         element.didAttachRenderers();
283 }
284
285 static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
286 {
287     const RenderStyle& currentStyle = renderer->style();
288
289     const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
290     if (!pseudoStyleCache)
291         return false;
292
293     for (auto& cache : *pseudoStyleCache) {
294         PseudoId pseudoId = cache->styleType();
295         std::unique_ptr<RenderStyle> newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
296         if (!newPseudoStyle)
297             return true;
298         if (*newPseudoStyle != *cache) {
299             newStyle->addCachedPseudoStyle(WTFMove(newPseudoStyle));
300             return true;
301         }
302     }
303     return false;
304 }
305
306 void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::ElementUpdate& update)
307 {
308 #if PLATFORM(IOS)
309     CheckForVisibilityChange checkForVisibilityChange(element);
310 #endif
311
312     bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.hasDisplayContents());
313     if (shouldTearDownRenderers) {
314         if (!element.renderer()) {
315             // We may be tearing down a descendant renderer cached in renderTreePosition.
316             renderTreePosition().invalidateNextSibling();
317         }
318
319         // display:none cancels animations.
320         auto teardownType = update.style->display() == NONE ? TeardownType::RendererUpdateCancelingAnimations : TeardownType::RendererUpdate;
321         tearDownRenderers(element, teardownType);
322
323         renderingParent().didCreateOrDestroyChildRenderer = true;
324     }
325
326     bool hasDisplayContents = update.style->display() == CONTENTS;
327     if (hasDisplayContents)
328         element.storeDisplayContentsStyle(RenderStyle::clonePtr(*update.style));
329     else
330         element.resetComputedStyle();
331
332     bool shouldCreateNewRenderer = !element.renderer() && !hasDisplayContents;
333     if (shouldCreateNewRenderer) {
334         if (element.hasCustomStyleResolveCallbacks())
335             element.willAttachRenderers();
336         createRenderer(element, RenderStyle::clone(*update.style));
337
338         renderingParent().didCreateOrDestroyChildRenderer = true;
339         return;
340     }
341
342     if (!element.renderer())
343         return;
344     auto& renderer = *element.renderer();
345
346     if (update.recompositeLayer) {
347         renderer.setStyle(RenderStyle::clone(*update.style), StyleDifferenceRecompositeLayer);
348         return;
349     }
350
351     if (update.change == Style::NoChange) {
352         if (pseudoStyleCacheIsInvalid(&renderer, update.style.get())) {
353             renderer.setStyle(RenderStyle::clone(*update.style), StyleDifferenceEqual);
354             return;
355         }
356         return;
357     }
358
359     renderer.setStyle(RenderStyle::clone(*update.style), StyleDifferenceEqual);
360 }
361
362 void RenderTreeUpdater::createRenderer(Element& element, RenderStyle&& style)
363 {
364     auto computeInsertionPosition = [this, &element] () {
365         renderTreePosition().computeNextSibling(element);
366         return renderTreePosition();
367     };
368     
369     if (!shouldCreateRenderer(element, renderTreePosition().parent()))
370         return;
371
372     if (!element.rendererIsNeeded(style))
373         return;
374
375     RenderTreePosition insertionPosition = computeInsertionPosition();
376     auto newRenderer = element.createElementRenderer(WTFMove(style), insertionPosition);
377     if (!newRenderer)
378         return;
379
380     if (!insertionPosition.parent().isChildAllowed(*newRenderer, newRenderer->style()))
381         return;
382
383     element.setRenderer(newRenderer.get());
384
385     newRenderer->initializeStyle();
386
387 #if ENABLE(FULLSCREEN_API)
388     if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
389         newRenderer = RenderFullScreen::wrapNewRenderer(m_builder, WTFMove(newRenderer), insertionPosition.parent(), m_document);
390         if (!newRenderer)
391             return;
392     }
393 #endif
394
395     m_builder.insertChild(insertionPosition, WTFMove(newRenderer));
396
397     if (AXObjectCache* cache = m_document.axObjectCache())
398         cache->updateCacheAfterNodeIsAttached(&element);
399 }
400
401 bool RenderTreeUpdater::textRendererIsNeeded(const Text& textNode)
402 {
403     auto& renderingParent = this->renderingParent();
404     auto& parentRenderer = renderingParent.renderTreePosition->parent();
405     if (!parentRenderer.canHaveChildren())
406         return false;
407     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
408         return false;
409     if (textNode.isEditingText())
410         return true;
411     if (!textNode.length())
412         return false;
413     if (!textNode.data().isAllSpecialCharacters<isHTMLSpace>())
414         return true;
415     if (is<RenderText>(renderingParent.previousChildRenderer))
416         return true;
417     // This text node has nothing but white space. We may still need a renderer in some cases.
418     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
419         return false;
420     if (parentRenderer.isFlexibleBox() && !parentRenderer.isRenderButton())
421         return false;
422     if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
423         return true;
424
425     auto* previousRenderer = renderingParent.previousChildRenderer;
426     if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
427         return false;
428
429     if (parentRenderer.isRenderInline()) {
430         // <span><div/> <div/></span>
431         if (previousRenderer && !previousRenderer->isInline())
432             return false;
433     } else {
434         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
435             return false;
436         
437         RenderObject* first = parentRenderer.firstChild();
438         while (first && first->isFloatingOrOutOfFlowPositioned())
439             first = first->nextSibling();
440         RenderObject* nextRenderer = textNode.renderer() ? textNode.renderer() :  renderTreePosition().nextSiblingRenderer(textNode);
441         if (!first || nextRenderer == first) {
442             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
443             return false;
444         }
445     }
446     return true;
447 }
448
449 void RenderTreeUpdater::createTextRenderer(Text& textNode, const Style::TextUpdate* textUpdate)
450 {
451     ASSERT(!textNode.renderer());
452
453     auto& renderTreePosition = this->renderTreePosition();
454     auto textRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
455
456     renderTreePosition.computeNextSibling(textNode);
457
458     if (!renderTreePosition.parent().isChildAllowed(*textRenderer, renderTreePosition.parent().style()))
459         return;
460
461     textNode.setRenderer(textRenderer.get());
462
463     if (textUpdate && textUpdate->inheritedDisplayContentsStyle && *textUpdate->inheritedDisplayContentsStyle) {
464         // Wrap text renderer into anonymous inline so we can give it a style.
465         // This is to support "<div style='display:contents;color:green'>text</div>" type cases
466         auto newDisplayContentsAnonymousWrapper = WebCore::createRenderer<RenderInline>(textNode.document(), RenderStyle::clone(**textUpdate->inheritedDisplayContentsStyle));
467         newDisplayContentsAnonymousWrapper->initializeStyle();
468         auto& displayContentsAnonymousWrapper = *newDisplayContentsAnonymousWrapper;
469         m_builder.insertChild(renderTreePosition, WTFMove(newDisplayContentsAnonymousWrapper));
470
471         textRenderer->setInlineWrapperForDisplayContents(&displayContentsAnonymousWrapper);
472         m_builder.insertChild(displayContentsAnonymousWrapper, WTFMove(textRenderer));
473         return;
474     }
475
476     m_builder.insertChild(renderTreePosition, WTFMove(textRenderer));
477 }
478
479 void RenderTreeUpdater::updateTextRenderer(Text& text, const Style::TextUpdate* textUpdate)
480 {
481     auto* existingRenderer = text.renderer();
482     bool needsRenderer = textRendererIsNeeded(text);
483
484     if (existingRenderer && textUpdate && textUpdate->inheritedDisplayContentsStyle) {
485         if (existingRenderer->inlineWrapperForDisplayContents() || *textUpdate->inheritedDisplayContentsStyle) {
486             // FIXME: We could update without teardown.
487             tearDownTextRenderer(text);
488             existingRenderer = nullptr;
489         }
490     }
491
492     if (existingRenderer) {
493         if (needsRenderer) {
494             if (textUpdate)
495                 existingRenderer->setTextWithOffset(text.data(), textUpdate->offset, textUpdate->length);
496             return;
497         }
498         tearDownTextRenderer(text);
499         renderingParent().didCreateOrDestroyChildRenderer = true;
500         return;
501     }
502     if (!needsRenderer)
503         return;
504     createTextRenderer(text, textUpdate);
505     renderingParent().didCreateOrDestroyChildRenderer = true;
506 }
507
508 void RenderTreeUpdater::storePreviousRenderer(Node& node)
509 {
510     auto* renderer = node.renderer();
511     if (!renderer)
512         return;
513     ASSERT(renderingParent().previousChildRenderer != renderer);
514     renderingParent().previousChildRenderer = renderer;
515 }
516
517 void RenderTreeUpdater::tearDownRenderers(Element& root)
518 {
519     RenderTreeBuilder builder;
520     tearDownRenderers(root, TeardownType::Full);
521 }
522
523 void RenderTreeUpdater::tearDownRenderer(Text& text)
524 {
525     RenderTreeBuilder builder;
526     tearDownTextRenderer(text);
527 }
528
529 void RenderTreeUpdater::tearDownRenderers(Element& root, TeardownType teardownType)
530 {
531     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
532
533     Vector<Element*, 30> teardownStack;
534
535     auto push = [&] (Element& element) {
536         if (element.hasCustomStyleResolveCallbacks())
537             element.willDetachRenderers();
538         teardownStack.append(&element);
539     };
540
541     auto& animationController = root.document().frame()->animation();
542
543     auto pop = [&] (unsigned depth) {
544         while (teardownStack.size() > depth) {
545             auto& element = *teardownStack.takeLast();
546
547             if (teardownType == TeardownType::Full || teardownType == TeardownType::RendererUpdateCancelingAnimations)
548                 animationController.cancelAnimations(element);
549
550             if (teardownType == TeardownType::Full)
551                 element.clearHoverAndActiveStatusBeforeDetachingRenderer();
552
553             GeneratedContent::removeBeforePseudoElement(element);
554             GeneratedContent::removeAfterPseudoElement(element);
555
556             if (auto* renderer = element.renderer()) {
557                 renderer->removeFromParentAndDestroyCleaningUpAnonymousWrappers();
558                 element.setRenderer(nullptr);
559             }
560             if (element.hasCustomStyleResolveCallbacks())
561                 element.didDetachRenderers();
562         }
563     };
564
565     push(root);
566
567     auto descendants = composedTreeDescendants(root);
568     for (auto it = descendants.begin(), end = descendants.end(); it != end; ++it) {
569         pop(it.depth());
570
571         if (is<Text>(*it)) {
572             tearDownTextRenderer(downcast<Text>(*it));
573             continue;
574         }
575
576         push(downcast<Element>(*it));
577     }
578
579     pop(0);
580 }
581
582 void RenderTreeUpdater::tearDownTextRenderer(Text& text)
583 {
584     auto* renderer = text.renderer();
585     if (!renderer)
586         return;
587     renderer->removeFromParentAndDestroyCleaningUpAnonymousWrappers();
588     text.setRenderer(nullptr);
589 }
590
591 RenderView& RenderTreeUpdater::renderView()
592 {
593     return *m_document.renderView();
594 }
595
596 #if PLATFORM(IOS)
597 static EVisibility elementImplicitVisibility(const Element& element)
598 {
599     auto* renderer = element.renderer();
600     if (!renderer)
601         return VISIBLE;
602
603     auto& style = renderer->style();
604
605     auto width = style.width();
606     auto height = style.height();
607     if ((width.isFixed() && width.value() <= 0) || (height.isFixed() && height.value() <= 0))
608         return HIDDEN;
609
610     auto top = style.top();
611     auto left = style.left();
612     if (left.isFixed() && width.isFixed() && -left.value() >= width.value())
613         return HIDDEN;
614
615     if (top.isFixed() && height.isFixed() && -top.value() >= height.value())
616         return HIDDEN;
617     return VISIBLE;
618 }
619
620 CheckForVisibilityChange::CheckForVisibilityChange(const Element& element)
621     : m_element(element)
622     , m_previousDisplay(element.renderStyle() ? element.renderStyle()->display() : NONE)
623     , m_previousVisibility(element.renderStyle() ? element.renderStyle()->visibility() : HIDDEN)
624     , m_previousImplicitVisibility(WKObservingContentChanges() && WKObservedContentChange() != WKContentVisibilityChange ? elementImplicitVisibility(element) : VISIBLE)
625 {
626 }
627
628 CheckForVisibilityChange::~CheckForVisibilityChange()
629 {
630     if (!WKObservingContentChanges())
631         return;
632     if (m_element.isInUserAgentShadowTree())
633         return;
634     auto* style = m_element.renderStyle();
635     if (!style)
636         return;
637     if ((m_previousDisplay == NONE && style->display() != NONE) || (m_previousVisibility == HIDDEN && style->visibility() != HIDDEN)
638         || (m_previousImplicitVisibility == HIDDEN && elementImplicitVisibility(m_element) == VISIBLE))
639         WKSetObservedContentChange(WKContentVisibilityChange);
640 }
641 #endif
642
643 }