summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
blob: b6573a49fa0d86628c8788d07d670513bb25258d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
 *
 * 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/layout/svg/layout_svg_text_path.h"

#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/svg/svg_animated_length.h"
#include "third_party/blink/renderer/core/svg/svg_path_element.h"
#include "third_party/blink/renderer/core/svg/svg_text_path_element.h"
#include "third_party/blink/renderer/platform/graphics/path.h"

namespace blink {

PathPositionMapper::PathPositionMapper(const Path& path,
                                       float computed_path_length,
                                       float start_offset)
    : position_calculator_(path),
      path_length_(computed_path_length),
      path_start_offset_(start_offset) {}

PathPositionMapper::PositionType PathPositionMapper::PointAndNormalAtLength(
    float length,
    FloatPoint& point,
    float& angle) {
  if (length < 0)
    return kBeforePath;
  if (length > path_length_)
    return kAfterPath;
  DCHECK_GE(length, 0);
  DCHECK_LE(length, path_length_);

  position_calculator_.PointAndNormalAtLength(length, point, angle);
  return kOnPath;
}

LayoutSVGTextPath::LayoutSVGTextPath(Element* element)
    : LayoutSVGInline(element) {}

bool LayoutSVGTextPath::IsChildAllowed(LayoutObject* child,
                                       const ComputedStyle&) const {
  NOT_DESTROYED();
  if (child->IsText())
    return SVGLayoutSupport::IsLayoutableTextNode(child);

  return child->IsSVGInline() && !child->IsSVGTextPath();
}

std::unique_ptr<PathPositionMapper> LayoutSVGTextPath::LayoutPath() const {
  NOT_DESTROYED();
  const auto& text_path_element = To<SVGTextPathElement>(*GetNode());
  Element* target_element = SVGURIReference::TargetElementFromIRIString(
      text_path_element.HrefString(), text_path_element.OriginatingTreeScope());

  const auto* path_element = DynamicTo<SVGPathElement>(target_element);
  if (!path_element)
    return nullptr;

  Path path_data = path_element->AsPath();
  if (path_data.IsEmpty())
    return nullptr;

  // Spec: The 'transform' attribute on the referenced 'path' ...
  // element represents a supplemental transformation relative to the current
  // user coordinate system for the current 'text' element, including any
  // adjustments to the current user coordinate system due to a possible
  // 'transform' property on the current 'text' element.
  // https://svgwg.org/svg2-draft/text.html#TextPathElement
  path_data.Transform(
      path_element->CalculateTransform(SVGElement::kIncludeMotionTransform));

  // Determine the length to resolve any percentage 'startOffset'
  // against - either 'pathLength' (author path length) or the
  // computed length of the path.
  float computed_path_length = path_data.length();
  float author_path_length = path_element->AuthorPathLength();
  float offset_scale = 1;
  if (!std::isnan(author_path_length)) {
    offset_scale = SVGGeometryElement::PathLengthScaleFactor(
        computed_path_length, author_path_length);
  } else {
    author_path_length = computed_path_length;
  }

  const SVGLength& start_offset =
      *text_path_element.startOffset()->CurrentValue();
  float path_start_offset = start_offset.ValueAsPercentage();
  if (start_offset.IsPercentage())
    path_start_offset *= author_path_length;

  path_start_offset *= offset_scale;

  return std::make_unique<PathPositionMapper>(path_data, computed_path_length,
                                              path_start_offset);
}

}  // namespace blink