Index: gpu/command_buffer/service/shader_manager.cc |
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc |
index b230581d6d1eb009fe6762e6e9c2229857b844a5..caac49431836be4087a043eed6283cbbc53e3090 100644 |
--- a/gpu/command_buffer/service/shader_manager.cc |
+++ b/gpu/command_buffer/service/shader_manager.cc |
@@ -4,6 +4,7 @@ |
#include "gpu/command_buffer/service/shader_manager.h" |
#include "base/logging.h" |
+#include "base/string_util.h" |
namespace gpu { |
namespace gles2 { |
@@ -151,6 +152,192 @@ void ShaderManager::UnuseShader(ShaderManager::ShaderInfo* info) { |
RemoveShaderInfoIfUnused(info); |
} |
+namespace { |
+ |
+// Strips comments from shader text. This allows non-ASCII characters |
+// to be used in comments without potentially breaking OpenGL |
+// implementations not expecting characters outside the GLSL ES set. |
+class Stripper { |
+ public: |
+ Stripper(const std::string& str) |
+ : parse_state_(kBeginningOfLine) |
+ , source_string_(str) |
+ , length_(str.length()) |
+ , position_(0) { |
+ Parse(); |
+ } |
+ |
+ const std::string& result() { |
+ return result_; |
+ } |
+ |
+ private: |
+ bool HasMoreCharacters() { |
+ return position_ < length_; |
+ } |
+ |
+ void Parse() { |
+ while (HasMoreCharacters()) { |
+ Process(Current()); |
+ // Process() might Advance the position. |
+ if (HasMoreCharacters()) { |
+ Advance(); |
+ } |
+ } |
+ } |
+ |
+ void Process(char); |
+ |
+ bool Peek(char* character) { |
+ DCHECK(character); |
+ if (position_ + 1 >= length_) { |
+ return false; |
+ } |
+ *character = source_string_[position_ + 1]; |
+ return true; |
+ } |
+ |
+ char Current() { |
+ DCHECK_LT(position_, length_); |
+ return source_string_[position_]; |
+ } |
+ |
+ void Advance() { |
+ ++position_; |
+ } |
+ |
+ bool IsNewline(char character) { |
+ // Don't attempt to canonicalize newline related characters. |
+ return (character == '\n' || character == '\r'); |
+ } |
+ |
+ void Emit(char character) { |
+ result_.push_back(character); |
+ } |
+ |
+ enum ParseState { |
+ // Have not seen an ASCII non-whitespace character yet on |
+ // this line. Possible that we might see a preprocessor |
+ // directive. |
+ kBeginningOfLine, |
+ |
+ // Have seen at least one ASCII non-whitespace character |
+ // on this line. |
+ kMiddleOfLine, |
+ |
+ // Handling a preprocessor directive. Passes through all |
+ // characters up to the end of the line. Disables comment |
+ // processing. |
+ kInPreprocessorDirective, |
+ |
+ // Handling a single-line comment. The comment text is |
+ // replaced with a single space. |
+ kInSingleLineComment, |
+ |
+ // Handling a multi-line comment. Newlines are passed |
+ // through to preserve line numbers. |
+ kInMultiLineComment |
+ }; |
+ |
+ ParseState parse_state_; |
+ std::string source_string_; |
+ unsigned length_; |
+ unsigned position_; |
+ std::string result_; |
+}; |
+ |
+void Stripper::Process(char c) { |
+ if (IsNewline(c)) { |
+ // No matter what state we are in, pass through newlines |
+ // so we preserve line numbers. |
+ Emit(c); |
+ |
+ if (parse_state_ != kInMultiLineComment) |
+ parse_state_ = kBeginningOfLine; |
+ |
+ return; |
+ } |
+ |
+ char temp = 0; |
+ switch (parse_state_) { |
+ case kBeginningOfLine: |
+ if (IsAsciiWhitespace(c)) { |
+ Emit(c); |
+ break; |
+ } |
+ |
+ if (c == '#') { |
+ parse_state_ = kInPreprocessorDirective; |
+ Emit(c); |
+ break; |
+ } |
+ |
+ // Transition to normal state and re-handle character. |
+ parse_state_ = kMiddleOfLine; |
+ Process(c); |
+ break; |
+ |
+ case kMiddleOfLine: |
+ if (c == '/' && Peek(&temp)) { |
+ if (temp == '/') { |
+ parse_state_ = kInSingleLineComment; |
+ Emit(' '); |
+ Advance(); |
+ break; |
+ } |
+ |
+ if (temp == '*') { |
+ parse_state_ = kInMultiLineComment; |
+ // Emit the comment start in case the user has |
+ // an unclosed comment and we want to later |
+ // signal an error. |
+ Emit('/'); |
+ Emit('*'); |
+ Advance(); |
+ break; |
+ } |
+ } |
+ |
+ Emit(c); |
+ break; |
+ |
+ case kInPreprocessorDirective: |
+ // No matter what the character is, just pass it |
+ // through. Do not Parse comments in this state. This |
+ // might not be the right thing to do long term, but it |
+ // should handle the #error preprocessor directive. |
+ Emit(c); |
+ break; |
+ |
+ case kInSingleLineComment: |
+ // The newline code at the top of this function takes care |
+ // of resetting our state when we get out of the |
+ // single-line comment. Swallow all other characters. |
+ break; |
+ |
+ case kInMultiLineComment: |
+ if (c == '*' && Peek(&temp) && temp == '/') { |
+ Emit('*'); |
+ Emit('/'); |
+ parse_state_ = kMiddleOfLine; |
+ Advance(); |
+ break; |
+ } |
+ |
+ // Swallow all other characters. Unclear whether we may |
+ // want or need to just Emit a space per character to try |
+ // to preserve column numbers for debugging purposes. |
+ break; |
+ } |
+} |
+ |
+} // anonymous namespace |
+ |
+std::string ShaderManager::StripComments(const std::string source) { |
+ Stripper stripper(source); |
+ return stripper.result(); |
+} |
+ |
} // namespace gles2 |
} // namespace gpu |