Commit cb2b7dc7 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

Add a UseCounter for letter-spacing usage

Bug: 267056
Change-Id: Id3a9d65ec0dab6558f3b8504592648f91bbf1316
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2351101
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797884}
parent 15c22fa8
...@@ -2711,6 +2711,7 @@ enum WebFeature { ...@@ -2711,6 +2711,7 @@ enum WebFeature {
kEmailFieldDetected_PredictedTypeMatch = 3380, kEmailFieldDetected_PredictedTypeMatch = 3380,
kPhoneFieldDetected_PredictedTypeMatch = 3381, kPhoneFieldDetected_PredictedTypeMatch = 3381,
kEmailFieldDetected_PatternMatch = 3382, kEmailFieldDetected_PatternMatch = 3382,
kLastLetterSpacingAffectsRendering = 3383,
// Add new features immediately above this line. Don't change assigned // Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots. // numbers of any item, and don't reuse removed slots.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_object.h"
...@@ -44,6 +45,87 @@ namespace blink { ...@@ -44,6 +45,87 @@ namespace blink {
namespace { namespace {
bool IsLeftAligned(const ComputedStyle& style) {
switch (style.GetTextAlign()) {
case ETextAlign::kStart:
return IsLtr(style.Direction());
case ETextAlign::kEnd:
return IsRtl(style.Direction());
case ETextAlign::kLeft:
case ETextAlign::kWebkitLeft:
return true;
case ETextAlign::kCenter:
case ETextAlign::kWebkitCenter:
case ETextAlign::kJustify:
case ETextAlign::kRight:
case ETextAlign::kWebkitRight:
return false;
}
NOTREACHED();
return false;
}
bool HasLetterSpacingWorkAround(const LayoutObject* layout_object,
bool first_line,
const LayoutBlockFlow* block_flow) {
// All we need to know is whether it computes to 0 or not, so any
// |maxmimum_value| can work.
const LayoutUnit maximum_value(100);
if (MinimumValueForLength(block_flow->StyleRef(first_line).TextIndent(),
maximum_value))
return true;
// Margin/padding maybe applied to <span> or to the containing block. Sum up
// to the containing block. ex.:
// <div style="letter-spacing: 1em">
// <span style="margin-left: 1em>text</span>
// </div>
LayoutUnit margin_padding_start;
LayoutUnit margin_padding_end;
DCHECK(!layout_object->IsText());
for (;; layout_object = layout_object->Parent()) {
const ComputedStyle& style = layout_object->StyleRef(first_line);
if (style.MayHavePadding() || style.MayHaveMargin()) {
margin_padding_start +=
MinimumValueForLength(style.MarginStart(), maximum_value) +
MinimumValueForLength(style.PaddingStart(), maximum_value);
margin_padding_end +=
MinimumValueForLength(style.MarginEnd(), maximum_value) +
MinimumValueForLength(style.PaddingEnd(), maximum_value);
}
if (layout_object == block_flow)
break;
}
return margin_padding_start != margin_padding_end;
}
bool ShouldReportLetterSpacingUseCounter(const LayoutObject* layout_object,
bool first_line,
const LayoutBlockFlow* block_flow) {
DCHECK(layout_object->IsText());
layout_object = layout_object->Parent();
const ComputedStyle& style = layout_object->StyleRef(first_line);
DCHECK(style.GetFont().GetFontDescription().LetterSpacing());
// Count only when the containing block has `letter-spacing`. For now, we
// don't count cases like:
// <div><span style="letter-spacing: 1em">text</span></div>
const ComputedStyle& block_style = block_flow->StyleRef(first_line);
if (layout_object != block_flow &&
!block_style.GetFont().GetFontDescription().LetterSpacing())
return false;
if (((layout_object->HasBoxDecorationBackground() ||
block_flow->HasBoxDecorationBackground() ||
!IsLeftAligned(block_style)) &&
HasLetterSpacingWorkAround(layout_object, first_line, block_flow)) ||
// Workaround for `text-decoration` is complicated, just include all.
!style.AppliedTextDecorations().IsEmpty())
return true;
return false;
}
// Estimate the number of NGInlineItem to minimize the vector expansions. // Estimate the number of NGInlineItem to minimize the vector expansions.
unsigned EstimateInlineItemsCount(const LayoutBlockFlow& block) { unsigned EstimateInlineItemsCount(const LayoutBlockFlow& block) {
unsigned count = 0; unsigned count = 0;
...@@ -1109,8 +1191,17 @@ void NGInlineNode::ShapeText(NGInlineItemsData* data, ...@@ -1109,8 +1191,17 @@ void NGInlineNode::ShapeText(NGInlineItemsData* data,
scoped_refptr<ShapeResult> shape_result = scoped_refptr<ShapeResult> shape_result =
shaper.Shape(start_item, end_offset); shaper.Shape(start_item, end_offset);
if (UNLIKELY(spacing.SetSpacing(font))) if (UNLIKELY(spacing.SetSpacing(font))) {
shape_result->ApplySpacing(spacing); shape_result->ApplySpacing(spacing);
if (spacing.LetterSpacing() &&
ShouldReportLetterSpacingUseCounter(
start_item.GetLayoutObject(),
start_item.StyleVariant() == NGStyleVariant::kFirstLine,
GetLayoutBlockFlow())) {
UseCounter::Count(GetDocument(),
WebFeature::kLastLetterSpacingAffectsRendering);
}
}
// If the text is from one item, use the ShapeResult as is. // If the text is from one item, use the ShapeResult as is.
if (end_offset == start_item.EndOffset()) { if (end_offset == start_item.EndOffset()) {
...@@ -1691,6 +1782,14 @@ void NGInlineNode::CheckConsistency() const { ...@@ -1691,6 +1782,14 @@ void NGInlineNode::CheckConsistency() const {
#endif #endif
} }
bool NGInlineNode::ShouldReportLetterSpacingUseCounterForTesting(
const LayoutObject* layout_object,
bool first_line,
const LayoutBlockFlow* block_flow) {
return ShouldReportLetterSpacingUseCounter(layout_object, first_line,
block_flow);
}
String NGInlineNode::ToString() const { String NGInlineNode::ToString() const {
return String::Format("NGInlineNode"); return String::Format("NGInlineNode");
} }
......
...@@ -127,6 +127,11 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode { ...@@ -127,6 +127,11 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
bool UseFirstLineStyle() const; bool UseFirstLineStyle() const;
void CheckConsistency() const; void CheckConsistency() const;
bool ShouldReportLetterSpacingUseCounterForTesting(
const LayoutObject* layout_object,
bool first_line,
const LayoutBlockFlow* block_flow);
String ToString() const; String ToString() const;
struct FloatingObject { struct FloatingObject {
......
...@@ -1318,4 +1318,72 @@ TEST_F(NGInlineNodeTest, ReusingRTLAsLTR) { ...@@ -1318,4 +1318,72 @@ TEST_F(NGInlineNodeTest, ReusingRTLAsLTR) {
TEST_ITEM_OFFSET_DIR(Items()[2], 10u, 10u, TextDirection::kLtr); TEST_ITEM_OFFSET_DIR(Items()[2], 10u, 10u, TextDirection::kLtr);
} }
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterFalse) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em; text-align: center">
text
</p>
)HTML");
auto* p = ToLayoutNGBlockFlow(GetLayoutObjectByElementId("p"));
EXPECT_FALSE(NGInlineNode(p).ShouldReportLetterSpacingUseCounterForTesting(
p->FirstChild(), /* first_line */ false, p));
}
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterCenterTextIndent) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em; text-align: center; text-indent: 1em">
text
</p>
)HTML");
auto* p = ToLayoutNGBlockFlow(GetLayoutObjectByElementId("p"));
EXPECT_TRUE(NGInlineNode(p).ShouldReportLetterSpacingUseCounterForTesting(
p->FirstChild(), /* first_line */ false, p));
}
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterCenterPadding) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em; text-align: center; padding-left: 1em">
text
</p>
)HTML");
auto* p = ToLayoutNGBlockFlow(GetLayoutObjectByElementId("p"));
EXPECT_TRUE(NGInlineNode(p).ShouldReportLetterSpacingUseCounterForTesting(
p->FirstChild(), /* first_line */ false, p));
}
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterRight) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em; text-align: right; margin-right: -1em">
text
</p>
)HTML");
auto* p = ToLayoutNGBlockFlow(GetLayoutObjectByElementId("p"));
EXPECT_TRUE(NGInlineNode(p).ShouldReportLetterSpacingUseCounterForTesting(
p->FirstChild(), /* first_line */ false, p));
}
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterBorder) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em">
<span id="span" style="border:1px solid; padding-left:1em">span</span>
</p>
)HTML");
auto* p = ToLayoutNGBlockFlow(GetLayoutObjectByElementId("p"));
const LayoutObject* span = GetLayoutObjectByElementId("span");
EXPECT_TRUE(NGInlineNode(p).ShouldReportLetterSpacingUseCounterForTesting(
span->SlowFirstChild(), /* first_line */ false, p));
}
TEST_F(NGInlineNodeTest, LetterSpacingUseCounterUnderline) {
SetBodyInnerHTML(R"HTML(
<p id="p" style="letter-spacing: 1em">
<span id="span" style="text-decoration: underline">span</span>
</p>
)HTML");
auto* p = ToLayoutNGBlockFlow(GetLayoutObjectByElementId("p"));
const LayoutObject* span = GetLayoutObjectByElementId("span");
EXPECT_TRUE(NGInlineNode(p).ShouldReportLetterSpacingUseCounterForTesting(
span->SlowFirstChild(), /* first_line */ false, p));
}
} // namespace blink } // namespace blink
...@@ -28720,6 +28720,7 @@ Called by update_use_counter_feature_enum.py.--> ...@@ -28720,6 +28720,7 @@ Called by update_use_counter_feature_enum.py.-->
<int value="3380" label="EmailFieldDetected_PredictedTypeMatch"/> <int value="3380" label="EmailFieldDetected_PredictedTypeMatch"/>
<int value="3381" label="PhoneFieldDetected_PredictedTypeMatch"/> <int value="3381" label="PhoneFieldDetected_PredictedTypeMatch"/>
<int value="3382" label="EmailFieldDetected_PatternMatch"/> <int value="3382" label="EmailFieldDetected_PatternMatch"/>
<int value="3383" label="LastLetterSpacingAffectsRendering"/>
</enum> </enum>
<enum name="FeaturePolicyAllowlistType"> <enum name="FeaturePolicyAllowlistType">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment