Rename StringBuilder::append(UChar32) to StringBuilder::appendCharacter(UChar32)...
[WebKit-https.git] / Source / WebCore / css / CSSMarkup.cpp
1 /*
2  * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2004-2012, 2016 Apple Inc. All rights reserved.
5  * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
6  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
7  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
9  * Copyright (C) 2012 Intel Corporation. All rights reserved.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB.  If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26
27 #include "config.h"
28 #include "CSSMarkup.h"
29
30 #include "CSSParserIdioms.h"
31 #include <wtf/HexNumber.h>
32 #include <wtf/text/StringBuilder.h>
33 #include <wtf/unicode/CharacterNames.h>
34
35 namespace WebCore {
36
37 template <typename CharacterType>
38 static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
39 {
40     const CharacterType* end = characters + length;
41
42     // -?
43     if (characters != end && characters[0] == '-')
44         ++characters;
45
46     // {nmstart}
47     if (characters == end || !isNameStartCodePoint(characters[0]))
48         return false;
49     ++characters;
50
51     // {nmchar}*
52     for (; characters != end; ++characters) {
53         if (!isNameCodePoint(characters[0]))
54             return false;
55     }
56
57     return true;
58 }
59
60 // "ident" from the CSS tokenizer, minus backslash-escape sequences
61 static bool isCSSTokenizerIdentifier(const String& string)
62 {
63     unsigned length = string.length();
64
65     if (!length)
66         return false;
67
68     if (string.is8Bit())
69         return isCSSTokenizerIdentifier(string.characters8(), length);
70     return isCSSTokenizerIdentifier(string.characters16(), length);
71 }
72
73 static void serializeCharacter(UChar32 c, StringBuilder& appendTo)
74 {
75     appendTo.append('\\');
76     appendTo.appendCharacter(c);
77 }
78
79 static void serializeCharacterAsCodePoint(UChar32 c, StringBuilder& appendTo)
80 {
81     appendTo.append('\\');
82     appendUnsignedAsHex(c, appendTo, Lowercase);
83     appendTo.append(' ');
84 }
85
86 void serializeIdentifier(const String& identifier, StringBuilder& appendTo, bool skipStartChecks)
87 {
88     bool isFirst = !skipStartChecks;
89     bool isSecond = false;
90     bool isFirstCharHyphen = false;
91     unsigned index = 0;
92     while (index < identifier.length()) {
93         UChar32 c = identifier.characterStartingAt(index);
94         if (!c) {
95             // Check for lone surrogate which characterStartingAt does not return.
96             c = identifier[index];
97         }
98
99         index += U16_LENGTH(c);
100
101         if (!c)
102             appendTo.append(replacementCharacter);
103         else if (c <= 0x1f || c == 0x7f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen))))
104             serializeCharacterAsCodePoint(c, appendTo);
105         else if (c == 0x2d && isFirst && index == identifier.length())
106             serializeCharacter(c, appendTo);
107         else if (0x80 <= c || c == 0x2d || c == 0x5f || (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a))
108             appendTo.appendCharacter(c);
109         else
110             serializeCharacter(c, appendTo);
111
112         if (isFirst) {
113             isFirst = false;
114             isSecond = true;
115             isFirstCharHyphen = (c == 0x2d);
116         } else if (isSecond)
117             isSecond = false;
118     }
119 }
120
121 void serializeString(const String& string, StringBuilder& appendTo)
122 {
123     appendTo.append('"');
124
125     unsigned index = 0;
126     while (index < string.length()) {
127         UChar32 c = string.characterStartingAt(index);
128         index += U16_LENGTH(c);
129
130         if (c <= 0x1f || c == 0x7f)
131             serializeCharacterAsCodePoint(c, appendTo);
132         else if (c == 0x22 || c == 0x5c)
133             serializeCharacter(c, appendTo);
134         else
135             appendTo.appendCharacter(c);
136     }
137
138     appendTo.append('"');
139 }
140
141 String serializeString(const String& string)
142 {
143     StringBuilder builder;
144     serializeString(string, builder);
145     return builder.toString();
146 }
147
148 String serializeURL(const String& string)
149 {
150     return "url(" + serializeString(string) + ")";
151 }
152
153 String serializeAsStringOrCustomIdent(const String& string)
154 {
155     if (isCSSTokenizerIdentifier(string)) {
156         StringBuilder builder;
157         serializeIdentifier(string, builder);
158         return builder.toString();
159     }
160     return serializeString(string);
161 }
162     
163 String serializeFontFamily(const String& string)
164 {
165     return isCSSTokenizerIdentifier(string) ? string : serializeString(string);
166 }
167
168 } // namespace WebCore