Commit af7076ff authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

[PE] Support 'pathLength' for <path>s referenced from <textPath>

A 'pathLength' attribute on a <path> referenced from <textPath> will
affect the starting offset on the path as computed from 'startOffset'
attribute.
Refactor the PathPositionMapper setup a bit so that the start offset is
computed together with all the other path related state.

Bug: 803127
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: Id12c88580dd74db403598d2aa05ac9764ad68cdb
Reviewed-on: https://chromium-review.googlesource.com/897626Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#533712}
parent 0a9c4fe3
......@@ -1764,8 +1764,6 @@ crbug.com/626703 [ Android ] virtual/media-gpu-accelerated/external/wpt/media-so
crbug.com/626703 external/wpt/css/css-display/display-contents-fieldset-nested-legend.html [ Failure ]
crbug.com/626703 external/wpt/css/css-ui/text-overflow-026.html [ Failure ]
crbug.com/626703 external/wpt/svg/path/closepath/segment-completing.svg [ Failure ]
crbug.com/626703 external/wpt/svg/path/distance/pathLength-positive.svg [ Failure ]
crbug.com/626703 external/wpt/svg/path/distance/pathLength-zero.svg [ Failure ]
crbug.com/626703 [ Android Mac10.10 ] virtual/mojo-localstorage/external/wpt/webstorage/storage_enumerate.html [ Crash ]
crbug.com/626703 external/wpt/css/css-values/lh-unit-002.html [ Failure ]
crbug.com/626703 external/wpt/css/css-values/lh-unit-001.html [ Failure ]
......
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="200" viewBox="0 0 300 200"
font-family="sans-serif" font-size="28">
<metadata>
<h:link rel="help" href="https://svgwg.org/svg2-draft/paths.html#PathLengthAttribute"/>
<h:link rel="match" href="pathLength-positive-ref.svg"/>
<h:meta name="assert" content="pathLength scales distance along the path"/>
</metadata>
<defs>
<path id="track" stroke="lightblue" fill="none" d="M 50 50 h 200" pathLength="2"/>
</defs>
<g>
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track" startOffset="0%">The quick brown fox</textPath>
</text>
</g>
<g transform="translate(0,50)">
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track" startOffset="50%">The quick brown fox</textPath>
</text>
</g>
<g transform="translate(0,100)">
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track" startOffset="-50%">The quick brown fox</textPath>
</text>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="200" viewBox="0 0 300 200"
font-family="sans-serif" font-size="28">
<defs>
<path id="track" stroke="lightblue" fill="none" d="M 50 50 h 200"/>
</defs>
<g>
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track">The quick brown fox</textPath>
</text>
</g>
<g transform="translate(0,50)">
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track">The quick brown fox</textPath>
</text>
</g>
<g transform="translate(0,100)">
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track">The quick brown fox</textPath>
</text>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="200" viewBox="0 0 300 200"
font-family="sans-serif" font-size="28">
<metadata>
<h:link rel="help" href="https://svgwg.org/svg2-draft/paths.html#PathLengthAttribute"/>
<h:link rel="match" href="pathLength-zero-percentage-ref.svg"/>
<h:meta name="assert" content="A value of zero is valid and must be treated as a scaling factor of infinity."/>
</metadata>
<defs>
<path id="track" stroke="lightblue" fill="none" d="M 50 50 h 200" pathLength="0"/>
</defs>
<g>
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track" startOffset="0%">The quick brown fox</textPath>
</text>
</g>
<g transform="translate(0,50)">
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track" startOffset="50%">The quick brown fox</textPath>
</text>
</g>
<g transform="translate(0,100)">
<use xlink:href="#track"/>
<text>
<textPath xlink:href="#track" startOffset="-50%">The quick brown fox</textPath>
</text>
</g>
</svg>
......@@ -30,10 +30,6 @@ class LineLayoutSVGTextPath : public LineLayoutSVGInline {
return ToSVGTextPath()->LayoutPath();
}
float CalculateStartOffset(float path_length) const {
return ToSVGTextPath()->CalculateStartOffset(path_length);
}
private:
LayoutSVGTextPath* ToSVGTextPath() {
return ToLayoutSVGTextPath(GetLayoutObject());
......
......@@ -23,12 +23,15 @@
#include "core/svg/SVGPathElement.h"
#include "core/svg/SVGTextPathElement.h"
#include "platform/graphics/Path.h"
#include <memory>
namespace blink {
PathPositionMapper::PathPositionMapper(const Path& path)
: position_calculator_(path), path_length_(path.length()) {}
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,
......@@ -40,6 +43,7 @@ PathPositionMapper::PositionType PathPositionMapper::PointAndNormalAtLength(
return kAfterPath;
DCHECK_GE(length, 0);
DCHECK_LE(length, path_length_);
position_calculator_.PointAndNormalAtLength(length, point, angle);
return kOnPath;
}
......@@ -65,31 +69,44 @@ std::unique_ptr<PathPositionMapper> LayoutSVGTextPath::LayoutPath() const {
if (!IsSVGPathElement(target_element))
return nullptr;
SVGPathElement& path_element = ToSVGPathElement(*target_element);
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 attribute on the
// current 'text' element. http://www.w3.org/TR/SVG/text.html#TextPathElement
// 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));
return PathPositionMapper::Create(path_data);
}
// 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;
}
float LayoutSVGTextPath::CalculateStartOffset(float path_length) const {
const SVGLength& start_offset =
*ToSVGTextPathElement(GetNode())->startOffset()->CurrentValue();
float text_path_start_offset = start_offset.ValueAsPercentage();
*text_path_element.startOffset()->CurrentValue();
float path_start_offset = start_offset.ValueAsPercentage();
if (start_offset.TypeWithCalcResolved() ==
CSSPrimitiveValue::UnitType::kPercentage)
text_path_start_offset *= path_length;
path_start_offset *= author_path_length;
path_start_offset *= offset_scale;
return text_path_start_offset;
return PathPositionMapper::Create(path_data, computed_path_length,
path_start_offset);
}
} // namespace blink
......@@ -34,8 +34,11 @@ class PathPositionMapper {
USING_FAST_MALLOC(PathPositionMapper);
public:
static std::unique_ptr<PathPositionMapper> Create(const Path& path) {
return WTF::WrapUnique(new PathPositionMapper(path));
static std::unique_ptr<PathPositionMapper> Create(const Path& path,
float computed_path_length,
float start_offset) {
return WTF::WrapUnique(
new PathPositionMapper(path, computed_path_length, start_offset));
}
enum PositionType {
......@@ -45,12 +48,16 @@ class PathPositionMapper {
};
PositionType PointAndNormalAtLength(float length, FloatPoint&, float& angle);
float length() const { return path_length_; }
float StartOffset() const { return path_start_offset_; }
private:
explicit PathPositionMapper(const Path&);
PathPositionMapper(const Path&,
float computed_path_length,
float start_offset);
Path::PositionCalculator position_calculator_;
float path_length_;
float path_start_offset_;
};
class LayoutSVGTextPath final : public LayoutSVGInline {
......@@ -58,7 +65,6 @@ class LayoutSVGTextPath final : public LayoutSVGInline {
explicit LayoutSVGTextPath(Element*);
std::unique_ptr<PathPositionMapper> LayoutPath() const;
float CalculateStartOffset(float) const;
bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
......
......@@ -172,8 +172,7 @@ void SVGTextLayoutEngine::BeginTextPathLayout(SVGInlineFlowBox* flow_box) {
text_path_ = text_path.LayoutPath();
if (!text_path_)
return;
text_path_start_offset_ =
text_path.CalculateStartOffset(text_path_->length());
text_path_start_offset_ = text_path_->StartOffset();
SVGTextPathChunkBuilder text_path_chunk_layout_builder;
text_path_chunk_layout_builder.ProcessTextChunks(
......
......@@ -138,20 +138,32 @@ float SVGGeometryElement::ComputePathLength() const {
return AsPath().length();
}
float SVGGeometryElement::PathLengthScaleFactor() const {
float SVGGeometryElement::AuthorPathLength() const {
if (!pathLength()->IsSpecified())
return 1;
return std::numeric_limits<float>::quiet_NaN();
float author_path_length = pathLength()->CurrentValue()->Value();
// https://svgwg.org/svg2-draft/paths.html#PathLengthAttribute
// "A negative value is an error"
if (author_path_length < 0)
return std::numeric_limits<float>::quiet_NaN();
return author_path_length;
}
float SVGGeometryElement::PathLengthScaleFactor() const {
float author_path_length = AuthorPathLength();
if (std::isnan(author_path_length))
return 1;
DCHECK(GetLayoutObject());
return PathLengthScaleFactor(ComputePathLength(), author_path_length);
}
float SVGGeometryElement::PathLengthScaleFactor(float computed_path_length,
float author_path_length) {
DCHECK(!std::isnan(author_path_length));
// If the computed path length is zero, then the scale factor will
// always be zero except if the author path length is also zero - in
// which case performing the division would yield a NaN. Avoid the
// division in this case and always return zero.
float computed_path_length = ComputePathLength();
if (!computed_path_length)
return 0;
// "A value of zero is valid and must be treated as a scaling factor
......
......@@ -50,11 +50,14 @@ class SVGGeometryElement : public SVGGraphicsElement {
Path ToClipPath() const;
SVGAnimatedNumber* pathLength() const { return path_length_.Get(); }
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
virtual float getTotalLength();
virtual SVGPointTearOff* getPointAtLength(float distance);
float AuthorPathLength() const;
float PathLengthScaleFactor() const;
virtual float ComputePathLength() const;
static float PathLengthScaleFactor(float computed_path_length,
float author_path_length);
void Trace(blink::Visitor*) override;
......@@ -65,6 +68,8 @@ class SVGGeometryElement : public SVGGraphicsElement {
private:
bool IsSVGGeometryElement() const final { return true; }
virtual float ComputePathLength() const;
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
Member<SVGAnimatedNumber> path_length_;
};
......
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