Changeset 257839 in webkit
- Timestamp:
- Mar 4, 2020, 4:11:13 AM (6 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 15 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/events/keypress-removed-node-expected.txt (modified) (1 diff)
-
LayoutTests/fast/events/keypress-removed-node.html (modified) (1 diff)
-
LayoutTests/fast/forms/autofocus-input-css-style-change.html (modified) (1 diff)
-
LayoutTests/fast/forms/focus-after-visibility-change-expected.txt (added)
-
LayoutTests/fast/forms/focus-after-visibility-change.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/accessibility/AXObjectCache.cpp (modified) (1 diff)
-
Source/WebCore/dom/Document.cpp (modified) (9 diffs)
-
Source/WebCore/dom/Element.cpp (modified) (5 diffs)
-
Source/WebCore/dom/Element.h (modified) (2 diffs)
-
Source/WebCore/editing/FrameSelection.cpp (modified) (1 diff)
-
Source/WebCore/html/HTMLAreaElement.cpp (modified) (1 diff)
-
Source/WebCore/html/HTMLSelectElement.cpp (modified) (5 diffs)
-
Source/WebCore/html/HTMLTextFormControlElement.cpp (modified) (1 diff)
-
Source/WebCore/html/shadow/SpinButtonElement.cpp (modified) (1 diff)
-
Source/WebCore/html/shadow/TextControlInnerElements.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r257836 r257839 1 2020-03-04 Antti Koivisto <antti@apple.com> 2 3 Avoid full style resolution on Element::focus() 4 https://bugs.webkit.org/show_bug.cgi?id=208504 5 6 Reviewed by Zalan Bujtas. 7 8 * fast/events/keypress-removed-node-expected.txt: 9 * fast/events/keypress-removed-node.html: 10 11 Modify the test so it is not sensitive to non-rendered whitespace changes 12 (caused by timing of render tree updates). 13 14 * fast/forms/autofocus-input-css-style-change.html: 15 16 Read the <input autofocus> :focus style in rAF as focusing happens asynchronously. This matches other browsers. 17 18 * fast/forms/focus-after-visibility-change-expected.txt: Added. 19 * fast/forms/focus-after-visibility-change.html: Added. 20 21 Add a simple test for visibility style change after renderer has already be created. 22 1 23 2020-03-04 Carlos Garcia Campos <cgarcia@igalia.com> 2 24 -
trunk/LayoutTests/fast/events/keypress-removed-node-expected.txt
r21687 r257839 1 1 This test verifies that a node does not retain keyboard focus after it has been removed from the DOM. 2 2 3 PASS: did not get keyboard event.3 PASS: did not get keyboard event. -
trunk/LayoutTests/fast/events/keypress-removed-node.html
r120792 r257839 1 1 <p>This test verifies that a node does not retain keyboard focus after it has 2 2 been removed from the DOM.</p> 3 <hr> 4 <input type="text"> 5 <pre id="console">PASS: did not get keyboard event.</pre> 3 <hr><input type="text"><pre id="console">PASS: did not get keyboard event.</pre> 6 4 7 5 <script> -
trunk/LayoutTests/fast/forms/autofocus-input-css-style-change.html
r121008 r257839 14 14 } 15 15 16 var test = document.getElementById("test"); 17 if (document.defaultView.getComputedStyle(test, null).getPropertyValue('background-color') == "rgb(0, 128, 0)") 18 result.innerHTML = "PASS"; 16 requestAnimationFrame(()=>{ 17 if (getComputedStyle(test, null).getPropertyValue('background-color') == "rgb(0, 128, 0)") 18 result.innerHTML = "PASS"; 19 }); 20 19 21 </script> 20 22 </body> -
trunk/Source/WebCore/ChangeLog
r257837 r257839 1 2020-03-04 Antti Koivisto <antti@apple.com> 2 3 Avoid full style resolution on Element::focus() 4 https://bugs.webkit.org/show_bug.cgi?id=208504 5 6 Reviewed by Zalan Bujtas. 7 8 Element::focus() currently triggers full style resolution both before (to compute element visibility) 9 and after (for no particular reason). 10 11 Resolving style can be costly if there are further DOM mutations that end up invalidating it again. 12 This patch adds a cheaper single-element way to computing visibility and uses it for focus(). 13 14 This appears to be 3-4% Speedometer progression. 15 16 Test: fast/forms/focus-after-visibility-change.html 17 18 * accessibility/AXObjectCache.cpp: 19 (WebCore::AXObjectCache::focusedUIElementForPage): 20 21 AX code assumes renderers have exist for focused element so ensure style is up to date. 22 23 * dom/Document.cpp: 24 (WebCore::Document::setFocusedElement): 25 26 Remove style resolution. 27 28 * dom/Element.cpp: 29 (WebCore::Element::isFocusable const): 30 31 Use isVisibleWithoutResolvingFullStyle helper. 32 33 (WebCore::Element::focus): 34 35 Avoid style resolution if the element is in a subtree that doesn't have renderers yet. 36 37 (WebCore::Element::resolveComputedStyle): 38 39 Add a mode where we bail out when we figure out we are in display:none subtree. 40 41 (WebCore::Element::hasValidStyle const): 42 43 See if we already have valid style. 44 45 (WebCore::Element::isVisibleWithoutResolvingFullStyle const): 46 47 Use computed style mechanism for subtrees that have no renderers yet. 48 49 (WebCore::Element::computedStyle): 50 * dom/Element.h: 51 * html/HTMLAreaElement.cpp: 52 (WebCore::HTMLAreaElement::isFocusable const): 53 54 Use isVisibleWithoutResolvingFullStyle here too. 55 56 * html/HTMLSelectElement.cpp: 57 (WebCore::HTMLSelectElement::platformHandleKeydownEvent): 58 (WebCore::HTMLSelectElement::menuListDefaultEventHandler): 59 60 Update style after explicit focus() calls to keep the existing behavior. 61 62 * html/HTMLTextFormControlElement.cpp: 63 (WebCore::HTMLTextFormControlElement::setRangeText): 64 65 Ensure the renderer is created. 66 67 * html/shadow/SpinButtonElement.cpp: 68 (WebCore::SpinButtonElement::forwardEvent): 69 70 Remove unneeded renderer test. 71 1 72 2020-03-04 Carlos Garcia Campos <cgarcia@igalia.com> 2 73 -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r257760 r257839 427 427 if (!focusedDocument) 428 428 return nullptr; 429 430 focusedDocument->updateStyleIfNeeded(); 429 431 430 432 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE) -
trunk/Source/WebCore/dom/Document.cpp
r257394 r257839 4276 4276 return false; 4277 4277 4278 bool focusChangeBlocked = false;4279 4278 RefPtr<Element> oldFocusedElement = WTFMove(m_focusedElement); 4280 4279 4281 4280 // Remove focus from the existing focus node (if any) 4282 4281 if (oldFocusedElement) { 4282 bool focusChangeBlocked = false; 4283 4283 4284 oldFocusedElement->setFocus(false); 4284 4285 setFocusNavigationStartingNode(nullptr); … … 4333 4334 // HTMLInputElement::didBlur just scrolls text fields back to the beginning. 4334 4335 // FIXME: This could be done asynchronusly. 4335 // Updating style may dispatch events due to PostResolutionCallback4336 if (eventsMode == FocusRemovalEventsMode::Dispatch)4337 updateStyleIfNeeded();4338 4336 downcast<HTMLInputElement>(*oldFocusedElement).didBlur(); 4339 4337 } 4338 4339 if (focusChangeBlocked) 4340 return false; 4340 4341 } 4341 4342 … … 4343 4344 if (&newFocusedElement->document() != this) { 4344 4345 // Bluring oldFocusedElement may have moved newFocusedElement across documents. 4345 focusChangeBlocked = true; 4346 goto SetFocusedNodeDone; 4346 return false; 4347 4347 } 4348 4348 if (newFocusedElement->isRootEditableElement() && !acceptsEditingFocus(*newFocusedElement)) { 4349 4349 // delegate blocks focus change 4350 focusChangeBlocked = true; 4351 goto SetFocusedNodeDone; 4350 return false; 4352 4351 } 4353 4352 // Set focus on the new node … … 4360 4359 if (m_focusedElement != newFocusedElement) { 4361 4360 // handler shifted focus 4362 focusChangeBlocked = true; 4363 goto SetFocusedNodeDone; 4361 return false; 4364 4362 } 4365 4363 … … 4368 4366 if (m_focusedElement != newFocusedElement) { 4369 4367 // handler shifted focus 4370 focusChangeBlocked = true; 4371 goto SetFocusedNodeDone; 4368 return false; 4372 4369 } 4373 4370 … … 4378 4375 if (m_focusedElement != newFocusedElement) { 4379 4376 // handler shifted focus 4380 focusChangeBlocked = true; 4381 goto SetFocusedNodeDone; 4377 return false; 4382 4378 } 4383 4379 … … 4387 4383 if (m_focusedElement != newFocusedElement) { 4388 4384 // handler shifted focus 4389 focusChangeBlocked = true; 4390 goto SetFocusedNodeDone; 4385 return false; 4391 4386 } 4392 4387 … … 4413 4408 } 4414 4409 4415 if ( !focusChangeBlocked &&m_focusedElement) {4410 if (m_focusedElement) { 4416 4411 // Create the AXObject cache in a focus change because GTK relies on it. 4417 4412 if (AXObjectCache* cache = axObjectCache()) … … 4419 4414 } 4420 4415 4421 if ( !focusChangeBlocked &&page())4416 if (page()) 4422 4417 page()->chrome().focusedElementChanged(m_focusedElement.get()); 4423 4418 4424 SetFocusedNodeDone: 4425 // Updating style may dispatch events due to PostResolutionCallback 4426 // FIXME: Why is synchronous style update needed here at all? 4427 if (eventsMode == FocusRemovalEventsMode::Dispatch) 4428 updateStyleIfNeeded(); 4429 return !focusChangeBlocked; 4419 return true; 4430 4420 } 4431 4421 -
trunk/Source/WebCore/dom/Element.cpp
r257188 r257839 608 608 609 609 if (!renderer()) { 610 // If the node is in a display:none tree it might say it needs style recalc but611 // the whole document is actually up to date.612 // FIXME: We should be able to assert !needsStyleRecalc() || !document().childNeedsStyleRecalc()613 // but it hits too frequently on websites like Gmail and Microsoft Exchange.614 615 610 // Elements in canvas fallback content are not rendered, but they are allowed to be 616 611 // focusable as long as their canvas is displayed and visible. 617 612 if (auto* canvas = ancestorsOfType<HTMLCanvasElement>(*this).first()) 618 return canvas->renderer() && canvas->renderer()->style().visibility() == Visibility::Visible; 619 } 620 621 // FIXME: Even if we are not visible, we might have a child that is visible. 622 // Hyatt wants to fix that some day with a "has visible content" flag or the like. 623 if (!renderer() || renderer()->style().visibility() != Visibility::Visible) 624 return false; 625 626 return true; 613 return canvas->isVisibleWithoutResolvingFullStyle(); 614 } 615 616 return isVisibleWithoutResolvingFullStyle(); 627 617 } 628 618 … … 2986 2976 2987 2977 RefPtr<Element> newTarget = this; 2988 if (document->haveStylesheetsLoaded()) 2978 2979 // If we don't have renderer yet, isFocusable will compute it without style update. 2980 // FIXME: Expand it to avoid style update in all cases. 2981 if (renderer() && document->haveStylesheetsLoaded()) 2989 2982 document->updateStyleIfNeeded(); 2990 2983 … … 3291 3284 } 3292 3285 3293 const RenderStyle & Element::resolveComputedStyle()3286 const RenderStyle* Element::resolveComputedStyle(ResolveComputedStyleMode mode) 3294 3287 { 3295 3288 ASSERT(isConnected()); … … 3315 3308 ElementRareData& rareData = element->ensureElementRareData(); 3316 3309 rareData.setComputedStyle(WTFMove(style)); 3317 } 3318 3319 return *computedStyle; 3310 3311 if (mode == ResolveComputedStyleMode::RenderedOnly && computedStyle->display() == DisplayType::None) 3312 return nullptr; 3313 } 3314 3315 return computedStyle; 3316 } 3317 3318 bool Element::hasValidStyle() const 3319 { 3320 if (!document().needsStyleRecalc()) 3321 return true; 3322 3323 if (document().hasPendingFullStyleRebuild()) 3324 return false; 3325 3326 for (auto& element : lineageOfType<Element>(*this)) { 3327 if (element.styleValidity() != Style::Validity::Valid) 3328 return false; 3329 } 3330 return true; 3331 } 3332 3333 bool Element::isVisibleWithoutResolvingFullStyle() const 3334 { 3335 if (renderStyle() || hasValidStyle()) 3336 return renderStyle() && renderStyle()->visibility() == Visibility::Visible; 3337 3338 // Compute style in yet unstyled subtree. 3339 auto* style = existingComputedStyle(); 3340 if (!style) 3341 style = const_cast<Element&>(*this).resolveComputedStyle(ResolveComputedStyleMode::RenderedOnly); 3342 3343 if (!style) 3344 return false; 3345 3346 if (style->display() == DisplayType::None || style->display() == DisplayType::Contents) 3347 return false; 3348 3349 if (style->visibility() != Visibility::Visible) 3350 return false; 3351 3352 for (auto& element : ancestorsOfType<Element>(*this)) { 3353 if (element.existingComputedStyle()->display() == DisplayType::None) 3354 return false; 3355 } 3356 3357 return true; 3320 3358 } 3321 3359 … … 3350 3388 auto* style = existingComputedStyle(); 3351 3389 if (!style) 3352 style = &resolveComputedStyle();3390 style = resolveComputedStyle(); 3353 3391 3354 3392 if (pseudoElementSpecifier != PseudoId::None) { -
trunk/Source/WebCore/dom/Element.h
r255383 r257839 344 344 bool needsStyleInvalidation() const; 345 345 346 bool hasValidStyle() const; 347 bool isVisibleWithoutResolvingFullStyle() const; 348 346 349 // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.) 347 350 bool styleAffectedByActive() const { return hasStyleFlag(ElementStyleFlag::StyleAffectedByActive); } … … 693 696 void removeShadowRoot(); 694 697 695 const RenderStyle& resolveComputedStyle(); 698 enum class ResolveComputedStyleMode { Normal, RenderedOnly }; 699 const RenderStyle* resolveComputedStyle(ResolveComputedStyleMode = ResolveComputedStyleMode::Normal); 696 700 const RenderStyle& resolvePseudoElementStyle(PseudoId); 697 701 -
trunk/Source/WebCore/editing/FrameSelection.cpp
r257188 r257839 370 370 setCaretRectNeedsUpdate(); 371 371 372 if (!newSelection.isNone() && !(options & DoNotSetFocus)) 372 if (!newSelection.isNone() && !(options & DoNotSetFocus)) { 373 auto* oldFocusedElement = m_frame->document()->focusedElement(); 373 374 setFocusedElementIfNeeded(); 375 // FIXME: Should not be needed. 376 if (m_frame->document()->focusedElement() != oldFocusedElement) 377 m_frame->document()->updateStyleIfNeeded(); 378 } 374 379 375 380 // Always clear the x position used for vertical arrow navigation. -
trunk/Source/WebCore/html/HTMLAreaElement.cpp
r248846 r257839 211 211 { 212 212 RefPtr<HTMLImageElement> image = imageElement(); 213 if (!image || !image-> renderer() || image->renderer()->style().visibility() != Visibility::Visible)213 if (!image || !image->isVisibleWithoutResolvingFullStyle()) 214 214 return false; 215 215 -
trunk/Source/WebCore/html/HTMLSelectElement.cpp
r254087 r257839 1101 1101 if (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up") { 1102 1102 focus(); 1103 document().updateStyleIfNeeded(); 1103 1104 // Calling focus() may cause us to lose our renderer. Return true so 1104 1105 // that our caller doesn't process the event further, but don't set … … 1199 1200 if (keyCode == ' ' || keyCode == '\r') { 1200 1201 focus(); 1202 document().updateStyleIfNeeded(); 1201 1203 1202 1204 // Calling focus() may remove the renderer or change the renderer type. … … 1216 1218 if (keyCode == ' ') { 1217 1219 focus(); 1220 document().updateStyleIfNeeded(); 1218 1221 1219 1222 // Calling focus() may remove the renderer or change the renderer type. … … 1244 1247 focus(); 1245 1248 #if !PLATFORM(IOS_FAMILY) 1249 document().updateStyleIfNeeded(); 1250 1246 1251 auto* renderer = this->renderer(); 1247 1252 if (is<RenderMenuList>(renderer)) { … … 1327 1332 if (event.type() == eventNames().mousedownEvent && is<MouseEvent>(event) && downcast<MouseEvent>(event).button() == LeftButton) { 1328 1333 focus(); 1334 document().updateStyleIfNeeded(); 1329 1335 1330 1336 // Calling focus() may remove or change our renderer, in which case we don't want to handle the event further. -
trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp
r257199 r257839 243 243 setInnerTextValue(text); 244 244 245 // FIXME: What should happen to the value (as in value()) if there's no renderer? 245 // FIXME: This shouldn't need synchronous style update, or renderer at all. 246 if (!renderer()) 247 document().updateStyleIfNeeded(); 248 246 249 if (!renderer()) 247 250 return { }; -
trunk/Source/WebCore/html/shadow/SpinButtonElement.cpp
r246490 r257839 158 158 void SpinButtonElement::forwardEvent(Event& event) 159 159 { 160 if (!renderBox())161 return;162 163 160 if (!is<WheelEvent>(event)) 164 161 return; -
trunk/Source/WebCore/html/shadow/TextControlInnerElements.cpp
r256725 r257839 226 226 input->select(); 227 227 #if !PLATFORM(IOS_FAMILY) 228 document().updateStyleIfNeeded(); 229 228 230 if (auto* renderer = input->renderer()) { 229 231 auto& searchFieldRenderer = downcast<RenderSearchField>(*renderer);
Note:
See TracChangeset
for help on using the changeset viewer.