Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/ArrayUtils.h"
8 :
9 : #include "SVGPointList.h"
10 : #include "nsCharSeparatedTokenizer.h"
11 : #include "nsTextFormatter.h"
12 : #include "SVGContentUtils.h"
13 :
14 : namespace mozilla {
15 :
16 : nsresult
17 28 : SVGPointList::CopyFrom(const SVGPointList& rhs)
18 : {
19 28 : if (!mItems.Assign(rhs.mItems, fallible)) {
20 0 : return NS_ERROR_OUT_OF_MEMORY;
21 : }
22 28 : return NS_OK;
23 : }
24 :
25 : void
26 0 : SVGPointList::GetValueAsString(nsAString& aValue) const
27 : {
28 0 : aValue.Truncate();
29 : char16_t buf[50];
30 0 : uint32_t last = mItems.Length() - 1;
31 0 : for (uint32_t i = 0; i < mItems.Length(); ++i) {
32 : // Would like to use aValue.AppendPrintf("%f,%f", item.mX, item.mY),
33 : // but it's not possible to always avoid trailing zeros.
34 0 : nsTextFormatter::snprintf(buf, ArrayLength(buf),
35 : u"%g,%g",
36 0 : double(mItems[i].mX), double(mItems[i].mY));
37 : // We ignore OOM, since it's not useful for us to return an error.
38 0 : aValue.Append(buf);
39 0 : if (i != last) {
40 0 : aValue.Append(' ');
41 : }
42 : }
43 0 : }
44 :
45 : nsresult
46 14 : SVGPointList::SetValueFromString(const nsAString& aValue)
47 : {
48 : // The spec says that the list is parsed and accepted up to the first error
49 : // encountered, so we must call CopyFrom even if an error occurs. We still
50 : // want to throw any error code from setAttribute if there's a problem
51 : // though, so we must take care to return any error code.
52 :
53 14 : nsresult rv = NS_OK;
54 :
55 28 : SVGPointList temp;
56 :
57 : nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
58 14 : tokenizer(aValue, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
59 :
60 340 : while (tokenizer.hasMoreTokens()) {
61 :
62 326 : const nsAString& token = tokenizer.nextToken();
63 :
64 : RangedPtr<const char16_t> iter =
65 163 : SVGContentUtils::GetStartRangedPtr(token);
66 : const RangedPtr<const char16_t> end =
67 163 : SVGContentUtils::GetEndRangedPtr(token);
68 :
69 : float x;
70 163 : if (!SVGContentUtils::ParseNumber(iter, end, x)) {
71 0 : rv = NS_ERROR_DOM_SYNTAX_ERR;
72 0 : break;
73 : }
74 :
75 : float y;
76 163 : if (iter == end) {
77 652 : if (!tokenizer.hasMoreTokens() ||
78 652 : !SVGContentUtils::ParseNumber(tokenizer.nextToken(), y)) {
79 0 : rv = NS_ERROR_DOM_SYNTAX_ERR;
80 0 : break;
81 : }
82 : } else {
83 : // It's possible for the token to be 10-30 which has
84 : // no separator but needs to be parsed as 10, -30
85 0 : const nsAString& leftOver = Substring(iter.get(), end.get());
86 0 : if (leftOver[0] != '-' || !SVGContentUtils::ParseNumber(leftOver, y)) {
87 0 : rv = NS_ERROR_DOM_SYNTAX_ERR;
88 0 : break;
89 : }
90 : }
91 163 : temp.AppendItem(SVGPoint(x, y));
92 : }
93 14 : if (tokenizer.separatorAfterCurrentToken()) {
94 0 : rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
95 : }
96 14 : nsresult rv2 = CopyFrom(temp);
97 14 : if (NS_FAILED(rv2)) {
98 0 : return rv2; // prioritize OOM error code over syntax errors
99 : }
100 14 : return rv;
101 : }
102 :
103 : } // namespace mozilla
|