| /* |
| * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |
| * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) |
| * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. |
| * All rights reserved. |
| * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
| * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> |
| * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. |
| * (http://www.torchmobile.com/) |
| * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
| * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
| * Copyright (C) 2013 Google Inc. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "third_party/blink/renderer/core/css/resolver/style_adjuster.h" |
| |
| #include "third_party/blink/renderer/core/css/resolver/style_resolver.h" |
| #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" |
| #include "third_party/blink/renderer/core/css/style_change_reason.h" |
| #include "third_party/blink/renderer/core/dom/container_node.h" |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/dom/element.h" |
| #include "third_party/blink/renderer/core/dom/node_computed_style.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/frame/local_frame_view.h" |
| #include "third_party/blink/renderer/core/frame/settings.h" |
| #include "third_party/blink/renderer/core/frame/use_counter.h" |
| #include "third_party/blink/renderer/core/html/forms/html_input_element.h" |
| #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h" |
| #include "third_party/blink/renderer/core/html/html_iframe_element.h" |
| #include "third_party/blink/renderer/core/html/html_image_element.h" |
| #include "third_party/blink/renderer/core/html/html_plugin_element.h" |
| #include "third_party/blink/renderer/core/html/html_table_cell_element.h" |
| #include "third_party/blink/renderer/core/html/media/html_media_element.h" |
| #include "third_party/blink/renderer/core/html_names.h" |
| #include "third_party/blink/renderer/core/layout/layout_object.h" |
| #include "third_party/blink/renderer/core/layout/layout_replaced.h" |
| #include "third_party/blink/renderer/core/layout/layout_theme.h" |
| #include "third_party/blink/renderer/core/style/computed_style.h" |
| #include "third_party/blink/renderer/core/style/computed_style_constants.h" |
| #include "third_party/blink/renderer/core/svg/svg_svg_element.h" |
| #include "third_party/blink/renderer/core/svg_names.h" |
| #include "third_party/blink/renderer/platform/length.h" |
| #include "third_party/blink/renderer/platform/runtime_enabled_features.h" |
| #include "third_party/blink/renderer/platform/transforms/transform_operations.h" |
| #include "third_party/blink/renderer/platform/wtf/assertions.h" |
| |
| namespace blink { |
| |
| using namespace HTMLNames; |
| |
| namespace { |
| |
| TouchAction AdjustTouchActionForElement(TouchAction touch_action, |
| const ComputedStyle& style, |
| Element* element) { |
| bool is_child_document = |
| element && element == element->GetDocument().documentElement() && |
| element->GetDocument().LocalOwner(); |
| if (style.ScrollsOverflow() || is_child_document) |
| return touch_action | TouchAction::kTouchActionPan; |
| return touch_action; |
| } |
| |
| // Returns true for elements that are either <img> or <svg> image or <video> |
| // that are not in an image or media document; returns false otherwise. |
| bool IsImageOrVideoElement(const Element* element) { |
| if ((IsHTMLImageElement(element) || IsSVGImageElement(element)) && |
| !element->GetDocument().IsImageDocument()) |
| return true; |
| if (IsHTMLVideoElement(element) && !element->GetDocument().IsMediaDocument()) |
| return true; |
| return false; |
| } |
| |
| bool ShouldForceLegacyLayout(const ComputedStyle& style, |
| const ComputedStyle& layout_parent_style, |
| const Element& element) { |
| // Form controls are not supported yet. |
| if (element.ShouldForceLegacyLayout()) |
| return true; |
| |
| // When the actual parent (to inherit style from) doesn't have a layout box |
| // (display:contents), it may not have been switched over to forcing legacy |
| // layout, even if it's inside a subtree that should use legacy. Check with |
| // the layout parent as well, so that we don't risk switching back to LayoutNG |
| // when we shouldn't. |
| if (layout_parent_style.ForceLegacyLayout()) |
| return true; |
| |
| const Document& document = element.GetDocument(); |
| |
| // TODO(layout-dev): Once LayoutNG handles inline content editable, we |
| // should get rid of following code fragment. |
| if (!RuntimeEnabledFeatures::EditingNGEnabled()) { |
| if (style.UserModify() != EUserModify::kReadOnly || document.InDesignMode()) |
| return true; |
| } |
| |
| if (style.Display() == EDisplay::kWebkitBox || |
| style.Display() == EDisplay::kWebkitInlineBox) |
| return true; |
| |
| if (!RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) { |
| // Disable NG for the entire subtree if we're establishing a block |
| // fragmentation context. |
| if (style.SpecifiesColumns() || |
| (style.IsOverflowPaged() && |
| &element != document.ViewportDefiningElement())) |
| return true; |
| if (document.Printing()) { |
| // This needs to be discovered on the root element. |
| DCHECK_EQ(element, document.documentElement()); |
| return true; |
| } |
| } |
| |
| // The custom container is laid out by the legacy engine. Its children may |
| // not establish new formatting contexts, so we need to protect against |
| // re-entering LayoutNG there. |
| if (style.Display() == EDisplay::kLayoutCustom || |
| style.Display() == EDisplay::kInlineLayoutCustom) |
| return true; |
| |
| // 'text-combine-upright' property is not supported yet. |
| if (style.HasTextCombine() && !style.IsHorizontalWritingMode()) |
| return true; |
| |
| return false; |
| } |
| |
| } // namespace |
| |
| static EDisplay EquivalentBlockDisplay(EDisplay display) { |
| switch (display) { |
| case EDisplay::kBlock: |
| case EDisplay::kTable: |
| case EDisplay::kWebkitBox: |
| case EDisplay::kFlex: |
| case EDisplay::kGrid: |
| case EDisplay::kListItem: |
| case EDisplay::kFlowRoot: |
| case EDisplay::kLayoutCustom: |
| return display; |
| case EDisplay::kInlineTable: |
| return EDisplay::kTable; |
| case EDisplay::kWebkitInlineBox: |
| return EDisplay::kWebkitBox; |
| case EDisplay::kInlineFlex: |
| return EDisplay::kFlex; |
| case EDisplay::kInlineGrid: |
| return EDisplay::kGrid; |
| case EDisplay::kInlineLayoutCustom: |
| return EDisplay::kLayoutCustom; |
| |
| case EDisplay::kContents: |
| case EDisplay::kInline: |
| case EDisplay::kInlineBlock: |
| case EDisplay::kTableRowGroup: |
| case EDisplay::kTableHeaderGroup: |
| case EDisplay::kTableFooterGroup: |
| case EDisplay::kTableRow: |
| case EDisplay::kTableColumnGroup: |
| case EDisplay::kTableColumn: |
| case EDisplay::kTableCell: |
| case EDisplay::kTableCaption: |
| return EDisplay::kBlock; |
| case EDisplay::kNone: |
| NOTREACHED(); |
| return display; |
| } |
| NOTREACHED(); |
| return EDisplay::kBlock; |
| } |
| |
| static bool IsOutermostSVGElement(const Element* element) { |
| return element && element->IsSVGElement() && |
| ToSVGElement(*element).IsOutermostSVGSVGElement(); |
| } |
| |
| // CSS requires text-decoration to be reset at each DOM element for |
| // inline blocks, inline tables, shadow DOM crossings, floating elements, |
| // and absolute or relatively positioned elements. Outermost <svg> roots are |
| // considered to be atomic inline-level. |
| static bool DoesNotInheritTextDecoration(const ComputedStyle& style, |
| const Element* element) { |
| return style.Display() == EDisplay::kInlineTable || |
| style.Display() == EDisplay::kInlineBlock || |
| style.Display() == EDisplay::kWebkitInlineBox || |
| IsAtShadowBoundary(element) || style.IsFloating() || |
| style.HasOutOfFlowPosition() || IsOutermostSVGElement(element) || |
| IsHTMLRTElement(element); |
| } |
| |
| // Certain elements (<a>, <font>) override text decoration colors. "The font |
| // element is expected to override the color of any text decoration that spans |
| // the text of the element to the used value of the element's 'color' property." |
| // (https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3) |
| // The <a> behavior is non-standard. |
| static bool OverridesTextDecorationColors(const Element* element) { |
| return element && |
| (IsHTMLFontElement(element) || IsHTMLAnchorElement(element)); |
| } |
| |
| // FIXME: This helper is only needed because pseudoStyleForElement passes a null |
| // element to adjustComputedStyle, so we can't just use element->isInTopLayer(). |
| static bool IsInTopLayer(const Element* element, const ComputedStyle& style) { |
| return (element && element->IsInTopLayer()) || |
| style.StyleType() == kPseudoIdBackdrop; |
| } |
| |
| static bool LayoutParentStyleForcesZIndexToCreateStackingContext( |
| const ComputedStyle& layout_parent_style) { |
| return layout_parent_style.IsDisplayFlexibleOrGridBox(); |
| } |
| |
| void StyleAdjuster::AdjustStyleForEditing(ComputedStyle& style) { |
| if (style.UserModify() != EUserModify::kReadWritePlaintextOnly) |
| return; |
| // Collapsing whitespace is harmful in plain-text editing. |
| if (style.WhiteSpace() == EWhiteSpace::kNormal) |
| style.SetWhiteSpace(EWhiteSpace::kPreWrap); |
| else if (style.WhiteSpace() == EWhiteSpace::kNowrap) |
| style.SetWhiteSpace(EWhiteSpace::kPre); |
| else if (style.WhiteSpace() == EWhiteSpace::kPreLine) |
| style.SetWhiteSpace(EWhiteSpace::kPreWrap); |
| } |
| |
| static void AdjustStyleForFirstLetter(ComputedStyle& style) { |
| if (style.StyleType() != kPseudoIdFirstLetter) |
| return; |
| |
| // Force inline display (except for floating first-letters). |
| style.SetDisplay(style.IsFloating() ? EDisplay::kBlock : EDisplay::kInline); |
| |
| // CSS2 says first-letter can't be positioned. |
| style.SetPosition(EPosition::kStatic); |
| } |
| |
| static void AdjustStyleForHTMLElement(ComputedStyle& style, |
| HTMLElement& element) { |
| // <div> and <span> are the most common elements on the web, we skip all the |
| // work for them. |
| if (IsHTMLDivElement(element) || IsHTMLSpanElement(element)) |
| return; |
| |
| if (IsHTMLTableCellElement(element)) { |
| if (style.WhiteSpace() == EWhiteSpace::kWebkitNowrap) { |
| // Figure out if we are really nowrapping or if we should just |
| // use normal instead. If the width of the cell is fixed, then |
| // we don't actually use NOWRAP. |
| if (style.Width().IsFixed()) |
| style.SetWhiteSpace(EWhiteSpace::kNormal); |
| else |
| style.SetWhiteSpace(EWhiteSpace::kNowrap); |
| } |
| return; |
| } |
| |
| if (auto* image = ToHTMLImageElementOrNull(element)) { |
| if (image->IsCollapsed() || style.Display() == EDisplay::kContents) |
| style.SetDisplay(EDisplay::kNone); |
| return; |
| } |
| |
| if (IsHTMLTableElement(element)) { |
| // Tables never support the -webkit-* values for text-align and will reset |
| // back to the default. |
| if (style.GetTextAlign() == ETextAlign::kWebkitLeft || |
| style.GetTextAlign() == ETextAlign::kWebkitCenter || |
| style.GetTextAlign() == ETextAlign::kWebkitRight) |
| style.SetTextAlign(ETextAlign::kStart); |
| return; |
| } |
| |
| if (IsHTMLFrameElement(element) || IsHTMLFrameSetElement(element)) { |
| // Frames and framesets never honor position:relative or position:absolute. |
| // This is necessary to fix a crash where a site tries to position these |
| // objects. They also never honor display nor floating. |
| style.SetPosition(EPosition::kStatic); |
| style.SetDisplay(EDisplay::kBlock); |
| style.SetFloating(EFloat::kNone); |
| return; |
| } |
| |
| if (IsHTMLFrameElementBase(element)) { |
| if (style.Display() == EDisplay::kContents) { |
| style.SetDisplay(EDisplay::kNone); |
| return; |
| } |
| // Frames cannot overflow (they are always the size we ask them to be). |
| // Some compositing code paths may try to draw scrollbars anyhow. |
| style.SetOverflowX(EOverflow::kVisible); |
| style.SetOverflowY(EOverflow::kVisible); |
| return; |
| } |
| |
| if (IsHTMLRTElement(element)) { |
| // Ruby text does not support float or position. This might change with |
| // evolution of the specification. |
| style.SetPosition(EPosition::kStatic); |
| style.SetFloating(EFloat::kNone); |
| return; |
| } |
| |
| if (IsHTMLLegendElement(element) && style.Display() != EDisplay::kContents) { |
| style.SetDisplay(EDisplay::kBlock); |
| return; |
| } |
| |
| if (IsHTMLMarqueeElement(element)) { |
| // For now, <marquee> requires an overflow clip to work properly. |
| style.SetOverflowX(EOverflow::kHidden); |
| style.SetOverflowY(EOverflow::kHidden); |
| return; |
| } |
| |
| if (IsHTMLTextAreaElement(element)) { |
| // Textarea considers overflow visible as auto. |
| style.SetOverflowX(style.OverflowX() == EOverflow::kVisible |
| ? EOverflow::kAuto |
| : style.OverflowX()); |
| style.SetOverflowY(style.OverflowY() == EOverflow::kVisible |
| ? EOverflow::kAuto |
| : style.OverflowY()); |
| if (style.Display() == EDisplay::kContents) |
| style.SetDisplay(EDisplay::kNone); |
| return; |
| } |
| |
| if (IsHTMLPlugInElement(element)) { |
| style.SetRequiresAcceleratedCompositingForExternalReasons( |
| ToHTMLPlugInElement(element).ShouldAccelerate()); |
| if (style.Display() == EDisplay::kContents) |
| style.SetDisplay(EDisplay::kNone); |
| return; |
| } |
| |
| if (style.Display() == EDisplay::kContents) { |
| // See https://drafts.csswg.org/css-display/#unbox-html |
| // Some of these elements are handled with other adjustments above. |
| if (IsHTMLBRElement(element) || IsHTMLWBRElement(element) || |
| IsHTMLMeterElement(element) || IsHTMLProgressElement(element) || |
| IsHTMLCanvasElement(element) || IsHTMLMediaElement(element) || |
| IsHTMLInputElement(element) || IsHTMLTextAreaElement(element) || |
| IsHTMLSelectElement(element)) { |
| style.SetDisplay(EDisplay::kNone); |
| } |
| } |
| } |
| |
| static void AdjustOverflow(ComputedStyle& style) { |
| DCHECK(style.OverflowX() != EOverflow::kVisible || |
| style.OverflowY() != EOverflow::kVisible); |
| |
| if (style.Display() == EDisplay::kTable || |
| style.Display() == EDisplay::kInlineTable) { |
| // Tables only support overflow:hidden and overflow:visible and ignore |
| // anything else, see https://drafts.csswg.org/css2/visufx.html#overflow. As |
| // a table is not a block container box the rules for resolving conflicting |
| // x and y values in CSS Overflow Module Level 3 do not apply. Arguably |
| // overflow-x and overflow-y aren't allowed on tables but all UAs allow it. |
| if (style.OverflowX() != EOverflow::kHidden) |
| style.SetOverflowX(EOverflow::kVisible); |
| if (style.OverflowY() != EOverflow::kHidden) |
| style.SetOverflowY(EOverflow::kVisible); |
| // If we are left with conflicting overflow values for the x and y axes on a |
| // table then resolve both to OverflowVisible. This is interoperable |
| // behaviour but is not specced anywhere. |
| if (style.OverflowX() == EOverflow::kVisible) |
| style.SetOverflowY(EOverflow::kVisible); |
| else if (style.OverflowY() == EOverflow::kVisible) |
| style.SetOverflowX(EOverflow::kVisible); |
| } else if (style.OverflowX() == EOverflow::kVisible && |
| style.OverflowY() != EOverflow::kVisible) { |
| // If either overflow value is not visible, change to auto. |
| // FIXME: Once we implement pagination controls, overflow-x should default |
| // to hidden if overflow-y is set to -webkit-paged-x or -webkit-page-y. For |
| // now, we'll let it default to auto so we can at least scroll through the |
| // pages. |
| style.SetOverflowX(EOverflow::kAuto); |
| } else if (style.OverflowY() == EOverflow::kVisible && |
| style.OverflowX() != EOverflow::kVisible) { |
| style.SetOverflowY(EOverflow::kAuto); |
| } |
| |
| // Menulists should have visible overflow |
| if (style.Appearance() == kMenulistPart) { |
| style.SetOverflowX(EOverflow::kVisible); |
| style.SetOverflowY(EOverflow::kVisible); |
| } |
| } |
| |
| static void AdjustStyleForDisplay(ComputedStyle& style, |
| const ComputedStyle& layout_parent_style, |
| Document* document) { |
| if (style.Display() == EDisplay::kBlock && !style.IsFloating()) |
| return; |
| |
| if (style.Display() == EDisplay::kContents) |
| return; |
| |
| // FIXME: Don't support this mutation for pseudo styles like first-letter or |
| // first-line, since it's not completely clear how that should work. |
| if (style.Display() == EDisplay::kInline && |
| style.StyleType() == kPseudoIdNone && |
| style.GetWritingMode() != layout_parent_style.GetWritingMode()) |
| style.SetDisplay(EDisplay::kInlineBlock); |
| |
| // We do not honor position: relative or sticky for table rows, headers, and |
| // footers. This is correct for position: relative in CSS2.1 (and caused a |
| // crash in containingBlock() on some sites) and position: sticky is defined |
| // as following position: relative behavior for table elements. It is |
| // incorrect for CSS3. |
| if ((style.Display() == EDisplay::kTableHeaderGroup || |
| style.Display() == EDisplay::kTableRowGroup || |
| style.Display() == EDisplay::kTableFooterGroup || |
| style.Display() == EDisplay::kTableRow) && |
| style.HasInFlowPosition()) |
| style.SetPosition(EPosition::kStatic); |
| |
| // Cannot support position: sticky for table columns and column groups because |
| // current code is only doing background painting through columns / column |
| // groups. |
| if ((style.Display() == EDisplay::kTableColumnGroup || |
| style.Display() == EDisplay::kTableColumn) && |
| style.GetPosition() == EPosition::kSticky) |
| style.SetPosition(EPosition::kStatic); |
| |
| // writing-mode does not apply to table row groups, table column groups, table |
| // rows, and table columns. |
| // FIXME: Table cells should be allowed to be perpendicular or flipped with |
| // respect to the table, though. |
| if (style.Display() == EDisplay::kTableColumn || |
| style.Display() == EDisplay::kTableColumnGroup || |
| style.Display() == EDisplay::kTableFooterGroup || |
| style.Display() == EDisplay::kTableHeaderGroup || |
| style.Display() == EDisplay::kTableRow || |
| style.Display() == EDisplay::kTableRowGroup || |
| style.Display() == EDisplay::kTableCell) |
| style.SetWritingMode(layout_parent_style.GetWritingMode()); |
| |
| // FIXME: Since we don't support block-flow on flexible boxes yet, disallow |
| // setting of block-flow to anything other than TopToBottomWritingMode. |
| // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support. |
| if (style.GetWritingMode() != WritingMode::kHorizontalTb && |
| (style.Display() == EDisplay::kWebkitBox || |
| style.Display() == EDisplay::kWebkitInlineBox)) |
| style.SetWritingMode(WritingMode::kHorizontalTb); |
| |
| if (layout_parent_style.IsDisplayFlexibleOrGridBox()) { |
| style.SetFloating(EFloat::kNone); |
| style.SetDisplay(EquivalentBlockDisplay(style.Display())); |
| |
| // We want to count vertical percentage paddings/margins on flex items |
| // because our current behavior is different from the spec and we want to |
| // gather compatibility data. |
| if (style.PaddingBefore().IsPercentOrCalc() || |
| style.PaddingAfter().IsPercentOrCalc()) { |
| UseCounter::Count(document, |
| WebFeature::kFlexboxPercentagePaddingVertical); |
| } |
| if (style.MarginBefore().IsPercentOrCalc() || |
| style.MarginAfter().IsPercentOrCalc()) { |
| UseCounter::Count(document, WebFeature::kFlexboxPercentageMarginVertical); |
| } |
| } else if (layout_parent_style.IsDisplayLayoutCustomBox()) { |
| // Blockify the children of a LayoutCustom. |
| style.SetDisplay(EquivalentBlockDisplay(style.Display())); |
| } |
| } |
| |
| static void AdjustEffectiveTouchAction(ComputedStyle& style, |
| const ComputedStyle& parent_style, |
| Element* element, |
| bool is_svg_root) { |
| TouchAction inherited_action = parent_style.GetEffectiveTouchAction(); |
| |
| bool is_replaced_canvas = |
| element && IsHTMLCanvasElement(element) && |
| element->GetDocument().GetFrame() && |
| element->GetDocument().CanExecuteScripts(kNotAboutToExecuteScript); |
| bool is_non_replaced_inline_elements = |
| style.IsDisplayInlineType() && |
| !(style.IsDisplayReplacedType() || is_svg_root || |
| IsHTMLImageElement(element) || is_replaced_canvas); |
| bool is_table_row_or_column = style.IsDisplayTableRowOrColumnType(); |
| bool is_layout_object_needed = |
| element && element->LayoutObjectIsNeeded(style); |
| |
| TouchAction element_touch_action = TouchAction::kTouchActionAuto; |
| // Touch actions are only supported by elements that support both the CSS |
| // width and height properties. |
| // See https://www.w3.org/TR/pointerevents/#the-touch-action-css-property. |
| if (!is_non_replaced_inline_elements && !is_table_row_or_column && |
| is_layout_object_needed) { |
| element_touch_action = style.GetTouchAction(); |
| } |
| |
| if (!element) { |
| style.SetEffectiveTouchAction(element_touch_action & inherited_action); |
| return; |
| } |
| |
| bool is_child_document = element == element->GetDocument().documentElement(); |
| |
| // Apply touch action inherited from parent frame. |
| if (is_child_document && element->GetDocument().GetFrame()) { |
| inherited_action &= |
| TouchAction::kTouchActionPan | |
| element->GetDocument().GetFrame()->InheritedEffectiveTouchAction(); |
| } |
| |
| // The effective touch action is the intersection of the touch-action values |
| // of the current element and all of its ancestors up to the one that |
| // implements the gesture. Since panning is implemented by the scroller it is |
| // re-enabled for scrolling elements. |
| // The panning-restricted cancellation should also apply to iframes, so we |
| // allow (panning & local touch action) on the first descendant element of a |
| // iframe element. |
| inherited_action = |
| AdjustTouchActionForElement(inherited_action, style, element); |
| |
| TouchAction enforced_by_policy = TouchAction::kTouchActionNone; |
| if (element->GetDocument().IsVerticalScrollEnforced()) |
| enforced_by_policy = TouchAction::kTouchActionPanY; |
| |
| // Apply the adjusted parent effective touch actions. |
| style.SetEffectiveTouchAction((element_touch_action & inherited_action) | |
| enforced_by_policy); |
| |
| // Propagate touch action to child frames. |
| if (element->IsFrameOwnerElement()) { |
| Frame* content_frame = ToHTMLFrameOwnerElement(element)->ContentFrame(); |
| if (content_frame) { |
| content_frame->SetInheritedEffectiveTouchAction( |
| style.GetEffectiveTouchAction()); |
| } |
| } |
| } |
| |
| void StyleAdjuster::AdjustComputedStyle(StyleResolverState& state, |
| Element* element) { |
| DCHECK(state.LayoutParentStyle()); |
| DCHECK(state.ParentStyle()); |
| ComputedStyle& style = state.StyleRef(); |
| const ComputedStyle& parent_style = *state.ParentStyle(); |
| const ComputedStyle& layout_parent_style = *state.LayoutParentStyle(); |
| |
| if (element && (style.Display() != EDisplay::kNone || |
| element->LayoutObjectIsNeeded(style))) { |
| // TODO(rakina): Move this attribute check somewhere else. |
| if (RuntimeEnabledFeatures::InvisibleDOMEnabled() && |
| !element->invisible().IsNull()) |
| style.SetDisplay(EDisplay::kNone); |
| else if (element->IsHTMLElement()) |
| AdjustStyleForHTMLElement(style, ToHTMLElement(*element)); |
| } |
| if (style.Display() != EDisplay::kNone) { |
| bool is_document_element = |
| element && element->GetDocument().documentElement() == element; |
| // Per the spec, position 'static' and 'relative' in the top layer compute |
| // to 'absolute'. Root elements that are in the top layer should just |
| // be left alone because the fullscreen.css doesn't apply any style to |
| // them. |
| if (IsInTopLayer(element, style) && !is_document_element && |
| (style.GetPosition() == EPosition::kStatic || |
| style.GetPosition() == EPosition::kRelative)) |
| style.SetPosition(EPosition::kAbsolute); |
| |
| // Absolute/fixed positioned elements, floating elements and the document |
| // element need block-like outside display. |
| if (style.Display() != EDisplay::kContents && |
| (style.HasOutOfFlowPosition() || style.IsFloating())) |
| style.SetDisplay(EquivalentBlockDisplay(style.Display())); |
| |
| if (is_document_element) |
| style.SetDisplay(EquivalentBlockDisplay(style.Display())); |
| |
| // We don't adjust the first letter style earlier because we may change the |
| // display setting in adjustStyeForTagName() above. |
| AdjustStyleForFirstLetter(style); |
| |
| AdjustStyleForDisplay(style, layout_parent_style, |
| element ? &element->GetDocument() : nullptr); |
| |
| // If this is a child of a LayoutCustom, we need the name of the parent |
| // layout function for invalidation purposes. |
| if (layout_parent_style.IsDisplayLayoutCustomBox()) { |
| style.SetDisplayLayoutCustomParentName( |
| layout_parent_style.DisplayLayoutCustomName()); |
| } |
| } else { |
| AdjustStyleForFirstLetter(style); |
| } |
| |
| // Make sure our z-index value is only applied if the object is positioned. |
| if (style.GetPosition() == EPosition::kStatic && |
| !LayoutParentStyleForcesZIndexToCreateStackingContext( |
| layout_parent_style)) { |
| style.SetIsStackingContext(false); |
| // TODO(alancutter): Avoid altering z-index here. |
| if (!style.HasAutoZIndex()) |
| style.SetZIndex(0); |
| } else if (!style.HasAutoZIndex()) { |
| style.SetIsStackingContext(true); |
| } |
| |
| if (style.OverflowX() != EOverflow::kVisible || |
| style.OverflowY() != EOverflow::kVisible) |
| AdjustOverflow(style); |
| |
| if (DoesNotInheritTextDecoration(style, element)) |
| style.ClearAppliedTextDecorations(); |
| else |
| style.RestoreParentTextDecorations(parent_style); |
| style.ApplyTextDecorations( |
| parent_style.VisitedDependentColor(GetCSSPropertyTextDecorationColor()), |
| OverridesTextDecorationColors(element)); |
| |
| // Cull out any useless layers and also repeat patterns into additional |
| // layers. |
| style.AdjustBackgroundLayers(); |
| style.AdjustMaskLayers(); |
| |
| // Let the theme also have a crack at adjusting the style. |
| if (style.HasAppearance()) |
| LayoutTheme::GetTheme().AdjustStyle(style, element); |
| |
| // If we have first-letter pseudo style, transitions, or animations, do not |
| // share this style. |
| if (style.HasPseudoStyle(kPseudoIdFirstLetter) || style.Transitions() || |
| style.Animations()) |
| style.SetUnique(); |
| |
| AdjustStyleForEditing(style); |
| |
| bool is_svg_root = false; |
| bool is_svg_element = element && element->IsSVGElement(); |
| |
| if (is_svg_element) { |
| is_svg_root = ToSVGElement(element)->IsOutermostSVGSVGElement(); |
| if (!is_svg_root) { |
| // Only the root <svg> element in an SVG document fragment tree honors css |
| // position. |
| style.SetPosition(ComputedStyleInitialValues::InitialPosition()); |
| } |
| |
| if (style.Display() == EDisplay::kContents && |
| (is_svg_root || |
| (!IsSVGSVGElement(element) && !IsSVGGElement(element) && |
| !IsSVGUseElement(element) && !IsSVGTSpanElement(element)))) { |
| // According to the CSS Display spec[1], nested <svg> elements, <g>, |
| // <use>, and <tspan> elements are not rendered and their children are |
| // "hoisted". For other elements display:contents behaves as display:none. |
| // |
| // [1] https://drafts.csswg.org/css-display/#unbox-svg |
| style.SetDisplay(EDisplay::kNone); |
| } |
| |
| // SVG text layout code expects us to be a block-level style element. |
| if ((IsSVGForeignObjectElement(*element) || IsSVGTextElement(*element)) && |
| style.IsDisplayInlineType()) |
| style.SetDisplay(EDisplay::kBlock); |
| |
| // Columns don't apply to svg text elements. |
| if (IsSVGTextElement(*element)) |
| style.ClearMultiCol(); |
| } |
| |
| // If this node is sticky it marks the creation of a sticky subtree, which we |
| // must track to properly handle document lifecycle in some cases. |
| // |
| // It is possible that this node is already in a sticky subtree (i.e. we have |
| // nested sticky nodes) - in that case the bit will already be set via |
| // inheritance from the ancestor and there is no harm to setting it again. |
| if (style.GetPosition() == EPosition::kSticky) |
| style.SetSubtreeIsSticky(true); |
| |
| // If the inherited value of justify-items includes the 'legacy' |
| // keyword (plus 'left', 'right' or 'center'), 'legacy' computes to |
| // the the inherited value. Otherwise, 'auto' computes to 'normal'. |
| if (parent_style.JustifyItemsPositionType() == ItemPositionType::kLegacy && |
| style.JustifyItemsPosition() == ItemPosition::kLegacy) { |
| style.SetJustifyItems(parent_style.JustifyItems()); |
| } |
| |
| AdjustEffectiveTouchAction(style, parent_style, element, is_svg_root); |
| |
| bool is_media_control = |
| element && element->ShadowPseudoId().StartsWith("-webkit-media-controls"); |
| if (is_media_control && style.Appearance() == kNoControlPart) { |
| // For compatibility reasons if the element is a media control and the |
| // -webkit-appearance is none then we should clear the background image. |
| if (!StyleResolver::HasAuthorBackground(state)) { |
| style.MutableBackgroundInternal().ClearImage(); |
| } |
| } |
| |
| if (element && style.TextOverflow() == ETextOverflow::kEllipsis) { |
| const AtomicString& pseudo_id = element->ShadowPseudoId(); |
| if (pseudo_id == "-webkit-input-placeholder" || |
| pseudo_id == "-internal-input-suggested") { |
| TextControlElement* text_control = |
| ToTextControl(element->OwnerShadowHost()); |
| DCHECK(text_control); |
| // TODO(futhark@chromium.org): We force clipping text overflow for focused |
| // input elements since we don't want to render ellipsis during editing. |
| // We should do this as a general solution which also includes |
| // contenteditable elements being edited. The computed style should not |
| // change, but LayoutBlockFlow::ShouldTruncateOverflowingText() should |
| // instead return false when text is being edited inside that block. |
| // https://crbug.com/814954 |
| style.SetTextOverflow(text_control->ValueForTextOverflow()); |
| } |
| } |
| |
| if (RuntimeEnabledFeatures::LayoutNGEnabled() && !style.ForceLegacyLayout() && |
| element && |
| ShouldForceLegacyLayout(style, layout_parent_style, *element)) { |
| style.SetForceLegacyLayout(true); |
| } |
| |
| // If intrinsically sized images or videos are disallowed by feature policy, |
| // use default size (300 x 150) instead. |
| if (IsImageOrVideoElement(element)) { |
| if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() && |
| element->GetDocument().GetFrame() && |
| (!style.Width().IsSpecified() || !style.Height().IsSpecified())) { |
| // This check will trigger reporting, so only do it if either width or |
| // height is unspecified. |
| if (!element->GetDocument().GetFrame()->IsFeatureEnabled( |
| mojom::FeaturePolicyFeature::kUnsizedMedia, |
| ReportOptions::kReportOnFailure)) { |
| if (!style.Width().IsSpecified()) { |
| style.SetLogicalWidth(Length(LayoutReplaced::kDefaultWidth, kFixed)); |
| } |
| if (!style.Height().IsSpecified()) { |
| style.SetLogicalHeight( |
| Length(LayoutReplaced::kDefaultHeight, kFixed)); |
| } |
| } |
| } |
| } |
| } |
| } // namespace blink |