diff options
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.cc | 233 |
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: |