blob: 5fa9ab239143f54f3fff0dd9c60222589ebb5a88 [file] [log] [blame]
/*
* 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_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 {
if (child->IsText())
return SVGLayoutSupport::IsLayoutableTextNode(child);
return child->IsSVGInline() && !child->IsSVGTextPath();
}
std::unique_ptr<PathPositionMapper> LayoutSVGTextPath::LayoutPath() const {
const SVGTextPathElement& text_path_element =
ToSVGTextPathElement(*GetNode());
Element* target_element = SVGURIReference::TargetElementFromIRIString(
text_path_element.HrefString(),
text_path_element.TreeScopeForIdResolution());
if (!IsSVGPathElement(target_element))
return nullptr;
const SVGPathElement& path_element = ToSVGPathElement(*target_element);
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.TypeWithCalcResolved() ==
CSSPrimitiveValue::UnitType::kPercentage)
path_start_offset *= author_path_length;
path_start_offset *= offset_scale;
return PathPositionMapper::Create(path_data, computed_path_length,
path_start_offset);
}
} // namespace blink