1 : /*
2 : * Copyright (C) 2011 Apple Inc. All rights reserved.
3 : * Copyright (C) 2011 Mozilla Corporation. All rights reserved.
4 : *
5 : * Redistribution and use in source and binary forms, with or without
6 : * modification, are permitted provided that the following conditions
7 : * are met:
8 : * 1. Redistributions of source code must retain the above copyright
9 : * notice, this list of conditions and the following disclaimer.
10 : * 2. Redistributions in binary form must reproduce the above copyright
11 : * notice, this list of conditions and the following disclaimer in the
12 : * documentation and/or other materials provided with the distribution.
13 : *
14 : * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 : * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 : */
26 :
27 : #ifndef WEBGLVALIDATESTRINGS_H_
28 : #define WEBGLVALIDATESTRINGS_H_
29 :
30 : #include "WebGLContext.h"
31 :
32 : namespace mozilla {
33 :
34 : // The following code was taken from the WebKit WebGL implementation,
35 : // which can be found here:
36 : // http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
37 : // Note that some modifications were done to adapt it to Mozilla.
38 : /****** BEGIN CODE TAKEN FROM WEBKIT ******/
39 0 : bool WebGLContext::ValidateGLSLCharacter(PRUnichar c)
40 : {
41 : // Printing characters are valid except " $ ` @ \ ' DEL.
42 0 : if (c >= 32 && c <= 126 &&
43 : c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
44 : {
45 0 : return true;
46 : }
47 :
48 : // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid.
49 0 : if (c >= 9 && c <= 13) {
50 0 : return true;
51 : }
52 :
53 0 : return false;
54 : }
55 :
56 : // Strips comments from shader text. This allows non-ASCII characters
57 : // to be used in comments without potentially breaking OpenGL
58 : // implementations not expecting characters outside the GLSL ES set.
59 0 : class StripComments {
60 : public:
61 0 : StripComments(const nsAString& str)
62 : : m_parseState(BeginningOfLine)
63 0 : , m_end(str.EndReading())
64 0 : , m_current(str.BeginReading())
65 0 : , m_position(0)
66 : {
67 0 : m_result.SetLength(str.Length());
68 0 : parse();
69 0 : }
70 :
71 0 : const nsTArray<PRUnichar>& result()
72 : {
73 0 : return m_result;
74 : }
75 :
76 0 : size_t length()
77 : {
78 0 : return m_position;
79 : }
80 :
81 : private:
82 0 : bool hasMoreCharacters()
83 : {
84 0 : return (m_current < m_end);
85 : }
86 :
87 0 : void parse()
88 : {
89 0 : while (hasMoreCharacters()) {
90 0 : process(current());
91 : // process() might advance the position.
92 0 : if (hasMoreCharacters())
93 0 : advance();
94 : }
95 0 : }
96 :
97 : void process(PRUnichar);
98 :
99 0 : bool peek(PRUnichar& character)
100 : {
101 0 : if (m_current + 1 >= m_end)
102 0 : return false;
103 0 : character = *(m_current + 1);
104 0 : return true;
105 : }
106 :
107 0 : PRUnichar current()
108 : {
109 : //ASSERT(m_position < m_length);
110 0 : return *m_current;
111 : }
112 :
113 0 : void advance()
114 : {
115 0 : ++m_current;
116 0 : }
117 :
118 0 : bool isNewline(PRUnichar character)
119 : {
120 : // Don't attempt to canonicalize newline related characters.
121 0 : return (character == '\n' || character == '\r');
122 : }
123 :
124 0 : void emit(PRUnichar character)
125 : {
126 0 : m_result[m_position++] = character;
127 0 : }
128 :
129 : enum ParseState {
130 : // Have not seen an ASCII non-whitespace character yet on
131 : // this line. Possible that we might see a preprocessor
132 : // directive.
133 : BeginningOfLine,
134 :
135 : // Have seen at least one ASCII non-whitespace character
136 : // on this line.
137 : MiddleOfLine,
138 :
139 : // Handling a preprocessor directive. Passes through all
140 : // characters up to the end of the line. Disables comment
141 : // processing.
142 : InPreprocessorDirective,
143 :
144 : // Handling a single-line comment. The comment text is
145 : // replaced with a single space.
146 : InSingleLineComment,
147 :
148 : // Handling a multi-line comment. Newlines are passed
149 : // through to preserve line numbers.
150 : InMultiLineComment
151 : };
152 :
153 : ParseState m_parseState;
154 : const PRUnichar* m_end;
155 : const PRUnichar* m_current;
156 : size_t m_position;
157 : nsTArray<PRUnichar> m_result;
158 : };
159 :
160 0 : void StripComments::process(PRUnichar c)
161 : {
162 0 : if (isNewline(c)) {
163 : // No matter what state we are in, pass through newlines
164 : // so we preserve line numbers.
165 0 : emit(c);
166 :
167 0 : if (m_parseState != InMultiLineComment)
168 0 : m_parseState = BeginningOfLine;
169 :
170 0 : return;
171 : }
172 :
173 0 : PRUnichar temp = 0;
174 0 : switch (m_parseState) {
175 : case BeginningOfLine:
176 : // If it's an ASCII space.
177 0 : if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
178 0 : emit(c);
179 0 : break;
180 : }
181 :
182 0 : if (c == '#') {
183 0 : m_parseState = InPreprocessorDirective;
184 0 : emit(c);
185 0 : break;
186 : }
187 :
188 : // Transition to normal state and re-handle character.
189 0 : m_parseState = MiddleOfLine;
190 0 : process(c);
191 0 : break;
192 :
193 : case MiddleOfLine:
194 0 : if (c == '/' && peek(temp)) {
195 0 : if (temp == '/') {
196 0 : m_parseState = InSingleLineComment;
197 0 : emit(' ');
198 0 : advance();
199 0 : break;
200 : }
201 :
202 0 : if (temp == '*') {
203 0 : m_parseState = InMultiLineComment;
204 : // Emit the comment start in case the user has
205 : // an unclosed comment and we want to later
206 : // signal an error.
207 0 : emit('/');
208 0 : emit('*');
209 0 : advance();
210 0 : break;
211 : }
212 : }
213 :
214 0 : emit(c);
215 0 : break;
216 :
217 : case InPreprocessorDirective:
218 : // No matter what the character is, just pass it
219 : // through. Do not parse comments in this state. This
220 : // might not be the right thing to do long term, but it
221 : // should handle the #error preprocessor directive.
222 0 : emit(c);
223 0 : break;
224 :
225 : case InSingleLineComment:
226 : // The newline code at the top of this function takes care
227 : // of resetting our state when we get out of the
228 : // single-line comment. Swallow all other characters.
229 0 : break;
230 :
231 : case InMultiLineComment:
232 0 : if (c == '*' && peek(temp) && temp == '/') {
233 0 : emit('*');
234 0 : emit('/');
235 0 : m_parseState = MiddleOfLine;
236 0 : advance();
237 0 : break;
238 : }
239 :
240 : // Swallow all other characters. Unclear whether we may
241 : // want or need to just emit a space per character to try
242 : // to preserve column numbers for debugging purposes.
243 0 : break;
244 : }
245 : }
246 :
247 : /****** END CODE TAKEN FROM WEBKIT ******/
248 :
249 : } // end namespace mozilla
250 :
251 : #endif // WEBGLVALIDATESTRINGS_H_
|