michael@0: /* michael@0: * Copyright (C) 2011 Apple Inc. All rights reserved. michael@0: * Copyright (C) 2011 Mozilla Corporation. All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * 1. Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * 2. Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY michael@0: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE michael@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR michael@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR michael@0: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, michael@0: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, michael@0: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR michael@0: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY michael@0: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: #ifndef WEBGLVALIDATESTRINGS_H_ michael@0: #define WEBGLVALIDATESTRINGS_H_ michael@0: michael@0: #include "WebGLContext.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: // The following code was taken from the WebKit WebGL implementation, michael@0: // which can be found here: michael@0: // http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121 michael@0: // Note that some modifications were done to adapt it to Mozilla. michael@0: /****** BEGIN CODE TAKEN FROM WEBKIT ******/ michael@0: bool WebGLContext::ValidateGLSLCharacter(char16_t c) michael@0: { michael@0: // Printing characters are valid except " $ ` @ \ ' DEL. michael@0: if (c >= 32 && c <= 126 && michael@0: c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'') michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid. michael@0: if (c >= 9 && c <= 13) { michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: // Strips comments from shader text. This allows non-ASCII characters michael@0: // to be used in comments without potentially breaking OpenGL michael@0: // implementations not expecting characters outside the GLSL ES set. michael@0: class StripComments { michael@0: public: michael@0: StripComments(const nsAString& str) michael@0: : m_parseState(BeginningOfLine) michael@0: , m_end(str.EndReading()) michael@0: , m_current(str.BeginReading()) michael@0: , m_position(0) michael@0: { michael@0: m_result.SetLength(str.Length()); michael@0: parse(); michael@0: } michael@0: michael@0: const nsTArray& result() michael@0: { michael@0: return m_result; michael@0: } michael@0: michael@0: size_t length() michael@0: { michael@0: return m_position; michael@0: } michael@0: michael@0: private: michael@0: bool hasMoreCharacters() michael@0: { michael@0: return (m_current < m_end); michael@0: } michael@0: michael@0: void parse() michael@0: { michael@0: while (hasMoreCharacters()) { michael@0: process(current()); michael@0: // process() might advance the position. michael@0: if (hasMoreCharacters()) michael@0: advance(); michael@0: } michael@0: } michael@0: michael@0: void process(char16_t); michael@0: michael@0: bool peek(char16_t& character) michael@0: { michael@0: if (m_current + 1 >= m_end) michael@0: return false; michael@0: character = *(m_current + 1); michael@0: return true; michael@0: } michael@0: michael@0: char16_t current() michael@0: { michael@0: //ASSERT(m_position < m_length); michael@0: return *m_current; michael@0: } michael@0: michael@0: void advance() michael@0: { michael@0: ++m_current; michael@0: } michael@0: michael@0: bool isNewline(char16_t character) michael@0: { michael@0: // Don't attempt to canonicalize newline related characters. michael@0: return (character == '\n' || character == '\r'); michael@0: } michael@0: michael@0: void emit(char16_t character) michael@0: { michael@0: m_result[m_position++] = character; michael@0: } michael@0: michael@0: enum ParseState { michael@0: // Have not seen an ASCII non-whitespace character yet on michael@0: // this line. Possible that we might see a preprocessor michael@0: // directive. michael@0: BeginningOfLine, michael@0: michael@0: // Have seen at least one ASCII non-whitespace character michael@0: // on this line. michael@0: MiddleOfLine, michael@0: michael@0: // Handling a preprocessor directive. Passes through all michael@0: // characters up to the end of the line. Disables comment michael@0: // processing. michael@0: InPreprocessorDirective, michael@0: michael@0: // Handling a single-line comment. The comment text is michael@0: // replaced with a single space. michael@0: InSingleLineComment, michael@0: michael@0: // Handling a multi-line comment. Newlines are passed michael@0: // through to preserve line numbers. michael@0: InMultiLineComment michael@0: }; michael@0: michael@0: ParseState m_parseState; michael@0: const char16_t* m_end; michael@0: const char16_t* m_current; michael@0: size_t m_position; michael@0: nsTArray m_result; michael@0: }; michael@0: michael@0: void StripComments::process(char16_t c) michael@0: { michael@0: if (isNewline(c)) { michael@0: // No matter what state we are in, pass through newlines michael@0: // so we preserve line numbers. michael@0: emit(c); michael@0: michael@0: if (m_parseState != InMultiLineComment) michael@0: m_parseState = BeginningOfLine; michael@0: michael@0: return; michael@0: } michael@0: michael@0: char16_t temp = 0; michael@0: switch (m_parseState) { michael@0: case BeginningOfLine: michael@0: // If it's an ASCII space. michael@0: if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) { michael@0: emit(c); michael@0: break; michael@0: } michael@0: michael@0: if (c == '#') { michael@0: m_parseState = InPreprocessorDirective; michael@0: emit(c); michael@0: break; michael@0: } michael@0: michael@0: // Transition to normal state and re-handle character. michael@0: m_parseState = MiddleOfLine; michael@0: process(c); michael@0: break; michael@0: michael@0: case MiddleOfLine: michael@0: if (c == '/' && peek(temp)) { michael@0: if (temp == '/') { michael@0: m_parseState = InSingleLineComment; michael@0: emit(' '); michael@0: advance(); michael@0: break; michael@0: } michael@0: michael@0: if (temp == '*') { michael@0: m_parseState = InMultiLineComment; michael@0: // Emit the comment start in case the user has michael@0: // an unclosed comment and we want to later michael@0: // signal an error. michael@0: emit('/'); michael@0: emit('*'); michael@0: advance(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: emit(c); michael@0: break; michael@0: michael@0: case InPreprocessorDirective: michael@0: // No matter what the character is, just pass it michael@0: // through. Do not parse comments in this state. This michael@0: // might not be the right thing to do long term, but it michael@0: // should handle the #error preprocessor directive. michael@0: emit(c); michael@0: break; michael@0: michael@0: case InSingleLineComment: michael@0: // The newline code at the top of this function takes care michael@0: // of resetting our state when we get out of the michael@0: // single-line comment. Swallow all other characters. michael@0: break; michael@0: michael@0: case InMultiLineComment: michael@0: if (c == '*' && peek(temp) && temp == '/') { michael@0: emit('*'); michael@0: emit('/'); michael@0: m_parseState = MiddleOfLine; michael@0: advance(); michael@0: break; michael@0: } michael@0: michael@0: // Swallow all other characters. Unclear whether we may michael@0: // want or need to just emit a space per character to try michael@0: // to preserve column numbers for debugging purposes. michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /****** END CODE TAKEN FROM WEBKIT ******/ michael@0: michael@0: } // end namespace mozilla michael@0: michael@0: #endif // WEBGLVALIDATESTRINGS_H_