1/*
2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
4 * Copyright (C) 2019 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#pragma once
23
24#include "SVGTransform.h"
25#include "SVGTransformable.h"
26#include "SVGValuePropertyList.h"
27
28namespace WebCore {
29
30class SVGTransformList final : public SVGValuePropertyList<SVGTransform> {
31 friend class SVGViewSpec;
32 using Base = SVGValuePropertyList<SVGTransform>;
33 using Base::Base;
34
35public:
36 static Ref<SVGTransformList> create()
37 {
38 return adoptRef(*new SVGTransformList());
39 }
40
41 static Ref<SVGTransformList> create(SVGPropertyOwner* owner, SVGPropertyAccess access)
42 {
43 return adoptRef(*new SVGTransformList(owner, access));
44 }
45
46 static Ref<SVGTransformList> create(const SVGTransformList& other, SVGPropertyAccess access)
47 {
48 return adoptRef(*new SVGTransformList(other, access));
49 }
50
51 ExceptionOr<Ref<SVGTransform>> createSVGTransformFromMatrix(const Ref<SVGMatrix>& matrix)
52 {
53 return SVGTransform::create(matrix->value());
54 }
55
56 ExceptionOr<RefPtr<SVGTransform>> consolidate()
57 {
58 auto result = canAlterList();
59 if (result.hasException())
60 return result.releaseException();
61 ASSERT(result.releaseReturnValue());
62
63 // Spec: If the list was empty, then a value of null is returned.
64 if (m_items.isEmpty())
65 return nullptr;
66
67 if (m_items.size() == 1)
68 return makeRefPtr(at(0).get());
69
70 auto newItem = SVGTransform::create(concatenate());
71 clearItems();
72
73 auto item = append(WTFMove(newItem));
74 commitChange();
75 return makeRefPtr(item.get());
76 }
77
78 void parse(const String& value)
79 {
80 clearItems();
81
82 auto upconvertedCharacters = StringView(value).upconvertedCharacters();
83 const UChar* start = upconvertedCharacters;
84 if (!parse(start, start + value.length()))
85 clearItems();
86 }
87
88 AffineTransform concatenate() const
89 {
90 AffineTransform result;
91 for (const auto& transform : m_items)
92 result *= transform->matrix()->value();
93 return result;
94 }
95
96 String valueAsString() const override
97 {
98 StringBuilder builder;
99 for (const auto& transfrom : m_items) {
100 if (builder.length())
101 builder.append(' ');
102
103 builder.append(transfrom->value().valueAsString());
104 }
105 return builder.toString();
106 }
107
108private:
109 bool parse(const UChar*& start, const UChar* end)
110 {
111 bool delimParsed = false;
112 while (start < end) {
113 delimParsed = false;
114 SVGTransformValue::SVGTransformType type = SVGTransformValue::SVG_TRANSFORM_UNKNOWN;
115 skipOptionalSVGSpaces(start, end);
116
117 if (!SVGTransformable::parseAndSkipType(start, end, type))
118 return false;
119
120 Ref<SVGTransform> transform = SVGTransform::create(type);
121 if (!SVGTransformable::parseTransformValue(type, start, end, transform->value()))
122 return false;
123
124 append(WTFMove(transform));
125 skipOptionalSVGSpaces(start, end);
126 if (start < end && *start == ',') {
127 delimParsed = true;
128 ++start;
129 }
130
131 skipOptionalSVGSpaces(start, end);
132 }
133 return !delimParsed;
134 }
135};
136
137} // namespace WebCore
138