Skip to content

Commit

Permalink
[@container] Walk ancestry if ::first-line style is null
Browse files Browse the repository at this point in the history
HasPseudoElementStyle may return true even if the element does not
currently apply any ::first-line rules because we
SetHasPseudoElementStyle when only container queries fail.

If we get a null ComputedStyle for an element which returns true for
HasPseudoElementStyle(kPseudoIdFirstLine), continue to walk ancestors to
look for the ::first-line style.

Bug: 1273913
Change-Id: I87b7f9c04f818f2d9c82c6eb417b81465f15d913
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3629362
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1001435}
  • Loading branch information
Rune Lillesveen authored and Chromium LUCI CQ committed May 10, 2022
1 parent 8892c18 commit f7e7475
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 41 deletions.
51 changes: 21 additions & 30 deletions third_party/blink/renderer/core/layout/layout_block.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#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/html/html_marquee_element.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_box.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
Expand Down Expand Up @@ -2085,40 +2084,32 @@ LayoutUnit LayoutBlock::InlineBlockBaseline(
return LayoutUnit(-1);
}

const LayoutBlock* LayoutBlock::EnclosingFirstLineStyleBlock() const {
const LayoutBlock* LayoutBlock::FirstLineStyleParentBlock() const {
NOT_DESTROYED();
auto* element = DynamicTo<Element>(GetNode());
if (element && element->ShadowPseudoId() ==
shadow_element_names::kPseudoInternalInputSuggested) {
// Disable ::first-line style for autofill previews. See
// crbug.com/1227170.
return nullptr;
}
const LayoutBlock* first_line_block = this;
bool has_pseudo = false;
while (true) {
has_pseudo =
first_line_block->StyleRef().HasPseudoElementStyle(kPseudoIdFirstLine);
if (has_pseudo)
break;
LayoutObject* parent_block = first_line_block->Parent();
if (first_line_block->IsAtomicInlineLevel() ||
first_line_block->IsFloatingOrOutOfFlowPositioned() || !parent_block ||
!parent_block->BehavesLikeBlockContainer())
break;
auto* parent_layout_block = DynamicTo<LayoutBlock>(parent_block);
const LayoutObject* first_child = parent_layout_block->FirstChild();
while (first_child->IsFloatingOrOutOfFlowPositioned())
first_child = first_child->NextSibling();
if (first_child != first_line_block)
break;
first_line_block = parent_layout_block;
}
// Inline blocks do not get ::first-line style from its containing blocks.
if (IsAtomicInlineLevel())
return nullptr;
// Floats and out of flow blocks do not get ::first-line style from its
// containing blocks.
if (IsFloatingOrOutOfFlowPositioned())
return nullptr;

LayoutObject* parent_block = first_line_block->Parent();
if (!parent_block || !parent_block->BehavesLikeBlockContainer())
return nullptr;

const LayoutBlock* parent_layout_block = To<LayoutBlock>(parent_block);

if (!has_pseudo)
// If we are not the first in-flow child of our parent, we cannot get
// ::first-line style from our ancestors.
const LayoutObject* first_child = parent_layout_block->FirstChild();
while (first_child->IsFloatingOrOutOfFlowPositioned())
first_child = first_child->NextSibling();
if (first_child != first_line_block)
return nullptr;

return first_line_block;
return parent_layout_block;
}

LayoutBlockFlow* LayoutBlock::NearestInnerBlockWithFirstLine() {
Expand Down
7 changes: 4 additions & 3 deletions third_party/blink/renderer/core/layout/layout_block.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,10 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
// </div>
// </div>

// Returns the nearest enclosing block (including this block) that contributes
// a first-line style to our first line.
const LayoutBlock* EnclosingFirstLineStyleBlock() const;
// Return the parent LayoutObject if it can contribute to our ::first-line
// style.
const LayoutBlock* FirstLineStyleParentBlock() const;

// Returns this block or the nearest inner block containing the actual first
// line.
LayoutBlockFlow* NearestInnerBlockWithFirstLine();
Expand Down
31 changes: 25 additions & 6 deletions third_party/blink/renderer/core/layout/layout_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include "third_party/blink/renderer/core/html/html_table_cell_element.h"
#include "third_party/blink/renderer/core/html/html_table_element.h"
#include "third_party/blink/renderer/core/html/image_document.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
Expand Down Expand Up @@ -3937,14 +3938,32 @@ const ComputedStyle* LayoutObject::FirstLineStyleWithoutFallback() const {

if (BehavesLikeBlockContainer()) {
if (const ComputedStyle* cached =
StyleRef().GetCachedPseudoElementStyle(kPseudoIdFirstLine))
StyleRef().GetCachedPseudoElementStyle(kPseudoIdFirstLine)) {
return cached;
}

if (Element* element = DynamicTo<Element>(GetNode())) {
if (element->ShadowPseudoId() ==
shadow_element_names::kPseudoInternalInputSuggested) {
// Disable ::first-line style for autofill previews. See
// crbug.com/1227170.
return nullptr;
}
}

if (const LayoutBlock* first_line_block =
To<LayoutBlock>(this)->EnclosingFirstLineStyleBlock()) {
if (first_line_block->Style() == Style()) {
return first_line_block->GetCachedPseudoElementStyle(
kPseudoIdFirstLine);
for (const LayoutBlock* first_line_block = To<LayoutBlock>(this);
first_line_block;
first_line_block = first_line_block->FirstLineStyleParentBlock()) {
const ComputedStyle& style = first_line_block->StyleRef();
if (!style.HasPseudoElementStyle(kPseudoIdFirstLine))
continue;
if (first_line_block == this) {
if (const ComputedStyle* cached =
first_line_block->GetCachedPseudoElementStyle(
kPseudoIdFirstLine)) {
return cached;
}
continue;
}

// We can't use first_line_block->GetCachedPseudoElementStyle() because
Expand Down
4 changes: 2 additions & 2 deletions third_party/blink/renderer/core/layout/layout_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -3726,8 +3726,8 @@ class CORE_EXPORT LayoutObject : public GarbageCollected<LayoutObject>,
AncestorSkipInfo* = nullptr) const;

// Returns the first line style declared in CSS. The style may be declared on
// an ancestor block (see EnclosingFirstLineStyleBlock()) that applies to this
// object. Returns nullptr if there is no applicable first line style.
// an ancestor block (see LayoutBlock::FirstLineStyleParentBlock) that applies
// to this object. Returns nullptr if there is no applicable first line style.
// Whether the style applies is based on CSS rules, regardless of whether this
// object is really in the first line which is unknown before layout.
const ComputedStyle* FirstLineStyleWithoutFallback() const;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!doctype html>
<title>CSS Test Reference</title>
<div style="color:green">This text should be green.</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<title>CSS Container Queries Test: Non-matching ::first-line in @container</title>
<link rel="help" href="https://drafts.csswg.org/css-contain-3/#container-queries">
<link rel="match" href="inner-first-line-non-matching-ref.html">
<style>
#outer::first-line { color: green }
@container (width > 99999px) {
#inner::first-line { color: red }
}
</style>
<div id="outer">
<div id="inner">This text should be green.</div>
</div>

0 comments on commit f7e7475

Please sign in to comment.