summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc233
1 files changed, 167 insertions, 66 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index 8e1a8ea3cfd..17a8ad3676c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/editing/bidi_adjustment.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
@@ -197,10 +198,10 @@ NGFragmentItem::NGFragmentItem(const NGFragmentItem& source)
case kText:
new (&text_) TextItem(source.text_);
break;
- case kSVGText:
- new (&svg_text_) SVGTextItem();
+ case kSvgText:
+ new (&svg_text_) SvgTextItem();
svg_text_.data =
- std::make_unique<NGSVGFragmentData>(*source.svg_text_.data);
+ std::make_unique<NGSvgFragmentData>(*source.svg_text_.data);
break;
case kGeneratedText:
new (&generated_text_) GeneratedTextItem(source.generated_text_);
@@ -239,8 +240,8 @@ NGFragmentItem::NGFragmentItem(NGFragmentItem&& source)
case kText:
new (&text_) TextItem(std::move(source.text_));
break;
- case kSVGText:
- new (&svg_text_) SVGTextItem(std::move(source.svg_text_));
+ case kSvgText:
+ new (&svg_text_) SvgTextItem(std::move(source.svg_text_));
break;
case kGeneratedText:
new (&generated_text_)
@@ -260,8 +261,8 @@ NGFragmentItem::~NGFragmentItem() {
case kText:
text_.~TextItem();
break;
- case kSVGText:
- svg_text_.~SVGTextItem();
+ case kSvgText:
+ svg_text_.~SvgTextItem();
break;
case kGeneratedText:
generated_text_.~GeneratedTextItem();
@@ -293,6 +294,14 @@ bool NGFragmentItem::IsAtomicInline() const {
return false;
}
+bool NGFragmentItem::IsBlockInInline() const {
+ if (Type() != kBox)
+ return false;
+ if (const NGPhysicalBoxFragment* box = BoxFragment())
+ return box->IsBlockInInline();
+ return false;
+}
+
bool NGFragmentItem::IsFloating() const {
if (const NGPhysicalBoxFragment* box = BoxFragment())
return box->IsFloating();
@@ -304,7 +313,7 @@ bool NGFragmentItem::IsEmptyLineBox() const {
}
bool NGFragmentItem::IsStyleGeneratedText() const {
- if (Type() == kText || Type() == kSVGText)
+ if (Type() == kText || Type() == kSvgText)
return GetLayoutObject()->IsStyleGenerated();
return false;
}
@@ -313,36 +322,85 @@ bool NGFragmentItem::IsGeneratedText() const {
return IsLayoutGeneratedText() || IsStyleGeneratedText();
}
+bool NGFragmentItem::IsFormattingContextRoot() const {
+ const NGPhysicalBoxFragment* box = BoxFragment();
+ return box && box->IsFormattingContextRoot();
+}
+
bool NGFragmentItem::IsListMarker() const {
return layout_object_ && layout_object_->IsLayoutNGOutsideListMarker();
}
-void NGFragmentItem::ConvertToSVGText(std::unique_ptr<NGSVGFragmentData> data,
+void NGFragmentItem::ConvertToSvgText(std::unique_ptr<NGSvgFragmentData> data,
const PhysicalRect& unscaled_rect,
bool is_hidden) {
DCHECK(RuntimeEnabledFeatures::SVGTextNGEnabled());
DCHECK_EQ(Type(), kText);
is_hidden_for_paint_ = is_hidden;
text_.~TextItem();
- new (&svg_text_) SVGTextItem();
+ new (&svg_text_) SvgTextItem();
svg_text_.data = std::move(data);
- type_ = kSVGText;
+ type_ = kSvgText;
+ rect_ = unscaled_rect;
+}
+
+void NGFragmentItem::SetSvgLineLocalRect(const PhysicalRect& unscaled_rect) {
+ DCHECK_EQ(Type(), kLine);
rect_ = unscaled_rect;
}
FloatRect NGFragmentItem::ObjectBoundingBox() const {
- if (Type() != kSVGText)
+ if (Type() != kSvgText)
return FloatRect(rect_);
- const float scaling_factor =
- To<LayoutSVGInlineText>(GetLayoutObject())->ScalingFactor();
- DCHECK_GT(scaling_factor, 0.0f);
- FloatRect item_rect = SVGFragmentData()->rect;
- if (HasSVGTransformForBoundingBox())
- item_rect = BuildSVGTransformForBoundingBox().MapRect(item_rect);
- item_rect.Scale(1 / scaling_factor);
+ FloatRect item_rect = SvgFragmentData()->rect;
+ if (HasSvgTransformForBoundingBox())
+ item_rect = BuildSvgTransformForBoundingBox().MapRect(item_rect);
+ item_rect.Scale(1 / SvgScalingFactor());
return item_rect;
}
+FloatQuad NGFragmentItem::SvgUnscaledQuad() const {
+ DCHECK_EQ(Type(), kSvgText);
+ FloatQuad quad =
+ BuildSvgTransformForBoundingBox().MapQuad(SvgFragmentData()->rect);
+ const float scaling_factor = SvgScalingFactor();
+ quad.Scale(1 / scaling_factor, 1 / scaling_factor);
+ return quad;
+}
+
+PhysicalOffset NGFragmentItem::MapPointInContainer(
+ const PhysicalOffset& point) const {
+ if (Type() != kSvgText || !HasSvgTransformForBoundingBox())
+ return point;
+ const float scaling_factor = SvgScalingFactor();
+ return PhysicalOffset::FromFloatPointRound(
+ BuildSvgTransformForBoundingBox()
+ .Inverse()
+ .MapPoint(FloatPoint(point).ScaledBy(scaling_factor))
+ .ScaledBy(1 / scaling_factor));
+}
+
+float NGFragmentItem::ScaleInlineOffset(LayoutUnit inline_offset) const {
+ if (Type() != kSvgText)
+ return inline_offset.ToFloat();
+ return inline_offset.ToFloat() * SvgScalingFactor() /
+ SvgFragmentData()->length_adjust_scale;
+}
+
+bool NGFragmentItem::Contains(const FloatPoint& position) const {
+ if (Type() != kSvgText)
+ return FloatRect(rect_).Contains(position);
+ const float scaling_factor = SvgScalingFactor();
+ FloatPoint scaled_position = position;
+ scaled_position.Scale(scaling_factor, scaling_factor);
+ FloatRect item_rect = SvgFragmentData()->rect;
+ if (!HasSvgTransformForBoundingBox())
+ return item_rect.Contains(scaled_position);
+ return BuildSvgTransformForBoundingBox()
+ .MapQuad(FloatQuad(item_rect))
+ .ContainsPoint(scaled_position);
+}
+
bool NGFragmentItem::HasNonVisibleOverflow() const {
if (const NGPhysicalBoxFragment* fragment = BoxFragment())
return fragment->HasNonVisibleOverflow();
@@ -412,14 +470,6 @@ PhysicalRect NGFragmentItem::SelfInkOverflow() const {
return ink_overflow_.Self(InkOverflowType(), Size());
}
-PhysicalRect NGFragmentItem::ContentsInkOverflow() const {
- if (const NGPhysicalBoxFragment* box_fragment = BoxFragment())
- return box_fragment->ContentsInkOverflow();
- if (!HasInkOverflow())
- return PhysicalRect();
- return ink_overflow_.Contents(InkOverflowType(), Size());
-}
-
PhysicalRect NGFragmentItem::InkOverflow() const {
if (const NGPhysicalBoxFragment* box_fragment = BoxFragment())
return box_fragment->InkOverflow();
@@ -433,7 +483,7 @@ PhysicalRect NGFragmentItem::InkOverflow() const {
const ShapeResultView* NGFragmentItem::TextShapeResult() const {
if (Type() == kText)
return text_.shape_result.get();
- if (Type() == kSVGText)
+ if (Type() == kSvgText)
return svg_text_.data->shape_result.get();
if (Type() == kGeneratedText)
return generated_text_.shape_result.get();
@@ -444,7 +494,7 @@ const ShapeResultView* NGFragmentItem::TextShapeResult() const {
NGTextOffset NGFragmentItem::TextOffset() const {
if (Type() == kText)
return text_.text_offset;
- if (Type() == kSVGText)
+ if (Type() == kSvgText)
return svg_text_.data->text_offset;
if (Type() == kGeneratedText)
return {0, generated_text_.text.length()};
@@ -477,7 +527,7 @@ StringView NGFragmentItem::Text(const NGFragmentItems& items) const {
return StringView(items.Text(UsesFirstLineStyle()), text_.text_offset.start,
text_.text_offset.Length());
}
- if (Type() == kSVGText) {
+ if (Type() == kSvgText) {
return StringView(items.Text(UsesFirstLineStyle()),
svg_text_.data->text_offset.start,
svg_text_.data->text_offset.Length());
@@ -494,7 +544,7 @@ NGTextFragmentPaintInfo NGFragmentItem::TextPaintInfo(
return {items.Text(UsesFirstLineStyle()), text_.text_offset.start,
text_.text_offset.end, text_.shape_result.get()};
}
- if (Type() == kSVGText) {
+ if (Type() == kSvgText) {
return {items.Text(UsesFirstLineStyle()), svg_text_.data->text_offset.start,
svg_text_.data->text_offset.end,
svg_text_.data->shape_result.get()};
@@ -517,13 +567,13 @@ TextDirection NGFragmentItem::ResolvedDirection() const {
return static_cast<TextDirection>(text_direction_);
}
-bool NGFragmentItem::HasSVGTransformForPaint() const {
- return Type() == kSVGText && (svg_text_.data->length_adjust_scale != 1.0f ||
+bool NGFragmentItem::HasSvgTransformForPaint() const {
+ return Type() == kSvgText && (svg_text_.data->length_adjust_scale != 1.0f ||
svg_text_.data->angle != 0.0f);
}
-bool NGFragmentItem::HasSVGTransformForBoundingBox() const {
- return Type() == kSVGText && svg_text_.data->angle != 0.0f;
+bool NGFragmentItem::HasSvgTransformForBoundingBox() const {
+ return Type() == kSvgText && svg_text_.data->angle != 0.0f;
}
// For non-<textPath>:
@@ -533,23 +583,23 @@ bool NGFragmentItem::HasSVGTransformForBoundingBox() const {
//
// (x, y) is the center of the rotation. The center points of a non-<textPath>
// character and a <textPath> character are different.
-AffineTransform NGFragmentItem::BuildSVGTransformForPaint() const {
- DCHECK_EQ(Type(), kSVGText);
+AffineTransform NGFragmentItem::BuildSvgTransformForPaint() const {
+ DCHECK_EQ(Type(), kSvgText);
if (svg_text_.data->in_text_path) {
if (svg_text_.data->angle == 0.0f)
- return BuildSVGTransformForLengthAdjust();
- return BuildSVGTransformForTextPath(BuildSVGTransformForLengthAdjust());
+ return BuildSvgTransformForLengthAdjust();
+ return BuildSvgTransformForTextPath(BuildSvgTransformForLengthAdjust());
}
- AffineTransform transform = BuildSVGTransformForBoundingBox();
- AffineTransform length_adjust = BuildSVGTransformForLengthAdjust();
+ AffineTransform transform = BuildSvgTransformForBoundingBox();
+ AffineTransform length_adjust = BuildSvgTransformForLengthAdjust();
if (!length_adjust.IsIdentity())
transform.PreMultiply(length_adjust);
return transform;
}
-AffineTransform NGFragmentItem::BuildSVGTransformForLengthAdjust() const {
- DCHECK_EQ(Type(), kSVGText);
- const NGSVGFragmentData& svg_data = *svg_text_.data;
+AffineTransform NGFragmentItem::BuildSvgTransformForLengthAdjust() const {
+ DCHECK_EQ(Type(), kSvgText);
+ const NGSvgFragmentData& svg_data = *svg_text_.data;
const bool is_horizontal = IsHorizontal();
AffineTransform scale_transform;
float scale = svg_data.length_adjust_scale;
@@ -572,10 +622,10 @@ AffineTransform NGFragmentItem::BuildSVGTransformForLengthAdjust() const {
return scale_transform;
}
-AffineTransform NGFragmentItem::BuildSVGTransformForTextPath(
+AffineTransform NGFragmentItem::BuildSvgTransformForTextPath(
const AffineTransform& length_adjust) const {
- DCHECK_EQ(Type(), kSVGText);
- const NGSVGFragmentData& svg_data = *svg_text_.data;
+ DCHECK_EQ(Type(), kSvgText);
+ const NGSvgFragmentData& svg_data = *svg_text_.data;
DCHECK(svg_data.in_text_path);
DCHECK_NE(svg_data.angle, 0.0f);
@@ -589,7 +639,7 @@ AffineTransform NGFragmentItem::BuildSVGTransformForTextPath(
// The rotation should be about the center of the baseline.
const auto font_baseline = Style().GetFontBaseline();
// |x| in the horizontal writing-mode and |y| in the vertical writing-mode
- // point the center of the baseline. See |NGSVGTextLayoutAlgorithm::
+ // point the center of the baseline. See |NGSvgTextLayoutAlgorithm::
// PositionOnPath()|.
float x = svg_data.rect.X();
float y = svg_data.rect.Y();
@@ -612,14 +662,14 @@ AffineTransform NGFragmentItem::BuildSVGTransformForTextPath(
//
// (x, y) is the center of the rotation. The center points of a non-<textPath>
// character and a <textPath> character are different.
-AffineTransform NGFragmentItem::BuildSVGTransformForBoundingBox() const {
- DCHECK_EQ(Type(), kSVGText);
- const NGSVGFragmentData& svg_data = *svg_text_.data;
+AffineTransform NGFragmentItem::BuildSvgTransformForBoundingBox() const {
+ DCHECK_EQ(Type(), kSvgText);
+ const NGSvgFragmentData& svg_data = *svg_text_.data;
AffineTransform transform;
if (svg_data.angle == 0.0f)
return transform;
if (svg_data.in_text_path)
- return BuildSVGTransformForTextPath(AffineTransform());
+ return BuildSvgTransformForTextPath(AffineTransform());
transform.Rotate(svg_data.angle);
const SimpleFontData* font_data =
@@ -639,6 +689,16 @@ AffineTransform NGFragmentItem::BuildSVGTransformForBoundingBox() const {
return transform;
}
+float NGFragmentItem::SvgScalingFactor() const {
+ const auto* svg_inline_text =
+ DynamicTo<LayoutSVGInlineText>(GetLayoutObject());
+ if (!svg_inline_text)
+ return 1.0f;
+ const float scaling_factor = svg_inline_text->ScalingFactor();
+ DCHECK_GT(scaling_factor, 0.0f);
+ return scaling_factor;
+}
+
String NGFragmentItem::ToString() const {
// TODO(yosin): Once |NGPaintFragment| is removed, we should get rid of
// following if-statements.
@@ -787,6 +847,10 @@ void NGFragmentItem::RecalcInkOverflow(
contents_rect.offset -= OffsetInContainerFragment();
if (Type() == kLine) {
+ const auto* const text_combine =
+ DynamicTo<LayoutNGTextCombine>(GetLayoutObject());
+ if (UNLIKELY(text_combine))
+ contents_rect = text_combine->AdjustRectForBoundingBox(contents_rect);
// Line boxes don't have self overflow. Compute content overflow only.
*self_and_contents_rect_out = UnionRect(LocalRect(), contents_rect);
ink_overflow_type_ =
@@ -837,11 +901,15 @@ LayoutUnit NGFragmentItem::InlinePositionForOffset(
DCHECK_EQ(1u, text.length());
if (!offset || UNLIKELY(IsRtl(Style().Direction())))
return LayoutUnit();
+ if (Type() == kSvgText) {
+ return LayoutUnit(IsHorizontal() ? SvgFragmentData()->rect.Width()
+ : SvgFragmentData()->rect.Height());
+ }
return IsHorizontal() ? Size().width : Size().height;
}
-LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text,
- unsigned offset) const {
+LayoutUnit NGFragmentItem::CaretInlinePositionForOffset(StringView text,
+ unsigned offset) const {
return InlinePositionForOffset(text, offset, LayoutUnit::FromFloatRound,
AdjustMidCluster::kToEnd);
}
@@ -869,31 +937,63 @@ std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets(
PhysicalRect NGFragmentItem::LocalRect(StringView text,
unsigned start_offset,
unsigned end_offset) const {
- if (start_offset == StartOffset() && end_offset == EndOffset())
- return LocalRect();
+ LayoutUnit width = Size().width;
+ LayoutUnit height = Size().height;
+ if (Type() == kSvgText) {
+ const NGSvgFragmentData& data = *SvgFragmentData();
+ if (IsHorizontal()) {
+ width = LayoutUnit(data.rect.Size().Width() / data.length_adjust_scale);
+ height = LayoutUnit(data.rect.Size().Height());
+ } else {
+ width = LayoutUnit(data.rect.Size().Width());
+ height = LayoutUnit(data.rect.Size().Height() / data.length_adjust_scale);
+ }
+ }
+ if (start_offset == StartOffset() && end_offset == EndOffset()) {
+ return {LayoutUnit(), LayoutUnit(), width, height};
+ }
LayoutUnit start_position, end_position;
std::tie(start_position, end_position) =
LineLeftAndRightForOffsets(text, start_offset, end_offset);
const LayoutUnit inline_size = end_position - start_position;
switch (GetWritingMode()) {
case WritingMode::kHorizontalTb:
- return {start_position, LayoutUnit(), inline_size, Size().height};
+ return {start_position, LayoutUnit(), inline_size, height};
case WritingMode::kVerticalRl:
case WritingMode::kVerticalLr:
case WritingMode::kSidewaysRl:
- return {LayoutUnit(), start_position, Size().width, inline_size};
+ return {LayoutUnit(), start_position, width, inline_size};
case WritingMode::kSidewaysLr:
- return {LayoutUnit(), Size().height - end_position, Size().width,
- inline_size};
+ return {LayoutUnit(), height - end_position, width, inline_size};
}
NOTREACHED();
return {};
}
+PhysicalRect NGFragmentItem::ComputeTextBoundsRectForHitTest(
+ const PhysicalOffset& inline_root_offset,
+ bool is_occlusion_test) const {
+ DCHECK(IsText());
+ const PhysicalOffset offset =
+ inline_root_offset + OffsetInContainerFragment();
+ const PhysicalRect border_rect(offset, Size());
+ if (UNLIKELY(is_occlusion_test)) {
+ PhysicalRect ink_overflow = SelfInkOverflow();
+ ink_overflow.Move(border_rect.offset);
+ return ink_overflow;
+ }
+ // We should not ignore fractional parts of border_rect in SVG because this
+ // item might have much larger screen size than border_rect.
+ // See svg/hittest/text-small-font-size.html.
+ if (Type() == kSvgText)
+ return border_rect;
+ return PhysicalRect(PixelSnappedIntRect(border_rect));
+}
+
PositionWithAffinity NGFragmentItem::PositionForPointInText(
const PhysicalOffset& point,
const NGInlineCursor& cursor) const {
- DCHECK(Type() == kText || Type() == kSVGText);
+ DCHECK(Type() == kText || Type() == kSvgText);
DCHECK_EQ(cursor.CurrentItem(), this);
if (IsGeneratedText())
return PositionWithAffinity();
@@ -904,7 +1004,7 @@ PositionWithAffinity NGFragmentItem::PositionForPointInText(
PositionWithAffinity NGFragmentItem::PositionForPointInText(
unsigned text_offset,
const NGInlineCursor& cursor) const {
- DCHECK(Type() == kText || Type() == kSVGText);
+ DCHECK(Type() == kText || Type() == kSvgText);
DCHECK_EQ(cursor.CurrentItem(), this);
DCHECK(!IsGeneratedText());
DCHECK_LE(text_offset, EndOffset());
@@ -921,15 +1021,16 @@ PositionWithAffinity NGFragmentItem::PositionForPointInText(
unsigned NGFragmentItem::TextOffsetForPoint(
const PhysicalOffset& point,
const NGFragmentItems& items) const {
- DCHECK(Type() == kText || Type() == kSVGText);
+ DCHECK(Type() == kText || Type() == kSvgText);
const ComputedStyle& style = Style();
const LayoutUnit& point_in_line_direction =
style.IsHorizontalWritingMode() ? point.left : point.top;
if (const ShapeResultView* shape_result = TextShapeResult()) {
+ float scaled_offset = ScaleInlineOffset(point_in_line_direction);
// TODO(layout-dev): Move caret logic out of ShapeResult into separate
// support class for code health and to avoid this copy.
return shape_result->CreateShapeResult()->CaretOffsetForHitTest(
- point_in_line_direction.ToFloat(), Text(items), BreakGlyphs) +
+ scaled_offset, Text(items), BreakGlyphs) +
StartOffset();
}
@@ -958,8 +1059,8 @@ std::ostream& operator<<(std::ostream& ostream, const NGFragmentItem& item) {
ostream << "Text " << item.StartOffset() << "-" << item.EndOffset() << " "
<< (IsLtr(item.ResolvedDirection()) ? "LTR" : "RTL");
break;
- case NGFragmentItem::kSVGText:
- ostream << "SVGText " << item.StartOffset() << "-" << item.EndOffset()
+ case NGFragmentItem::kSvgText:
+ ostream << "SvgText " << item.StartOffset() << "-" << item.EndOffset()
<< " " << (IsLtr(item.ResolvedDirection()) ? "LTR" : "RTL");
break;
case NGFragmentItem::kGeneratedText: