Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / gl / GrGLSLPrettyPrint.cpp
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "gl/GrGLSLPrettyPrint.h"
8
9 namespace GrGLSLPrettyPrint {
10
11 class GLSLPrettyPrint {
12 public:
13     GLSLPrettyPrint() {}
14
15     SkString prettify(const SkString& input, bool countlines) {
16         // setup pretty state
17         fIndex = 0;
18         fLength = input.size();
19         fInput = input;
20         fCountlines = countlines;
21         fTabs = 0;
22         fLinecount = 1;
23         fFreshline = true;
24
25         int parensDepth = 0;
26         // number 1st line
27         this->lineNumbering();
28         while (fLength > fIndex) {
29             /* the heart and soul of our prettification algorithm.  The rules should hopefully be
30              * self explanatory.  For '#' and '//' tokens we parse until we reach a newline.
31              *
32              * For long style comments like this one, we search for the ending token.  We also
33              * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines
34              * ourselves.  This allows us to remain in control of line numbers, and matching tabs
35              * Existing tabs in the input string are copied over too, but this will look funny
36              *
37              * '{' and '}' are handled in basically the same way.  We add a newline if we aren't
38              * on a fresh line, dirty the line, then add a second newline, ie braces are always
39              * on their own lines indented properly.  The one funkiness here is structs print with
40              * the semicolon on its own line.  Its not a problem for a glsl compiler though
41              *
42              * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala
43              * in for loops.
44              *
45              * ';' means add a new line
46              *
47              * '\t' and '\n' are ignored in general parsing for backwards compatability with
48              * existing shader code and we also have a special case for handling whitespace
49              * at the beginning of fresh lines.
50              *
51              * Otherwise just add the new character to the pretty string, indenting if necessary.
52              */
53             if (this->hasToken("#") || this->hasToken("//")) {
54                 this->parseUntilNewline();
55             } else if (this->hasToken("/*")) {
56                 this->parseUntil("*/");
57             } else if ('{' == fInput[fIndex]) {
58                 this->newline();
59                 this->appendChar('{');
60                 fTabs++;
61                 this->newline();
62             } else if ('}' == fInput[fIndex]) {
63                 fTabs--;
64                 this->newline();
65                 this->appendChar('}');
66                 this->newline();
67             } else if (this->hasToken(")")) {
68                 parensDepth--;
69             } else if (this->hasToken("(")) {
70                 parensDepth++;
71             } else if (!parensDepth && this->hasToken(";")) {
72                 this->newline();
73             } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] ||
74                     (fFreshline && ' ' == fInput[fIndex])) {
75                 fIndex++;
76             } else {
77                 this->appendChar(input[fIndex]);
78             }
79         }
80         return fPretty;
81     }
82 private:
83     void appendChar(char c) {
84         this->tabString();
85         fPretty.appendf("%c", fInput[fIndex++]);
86         fFreshline = false;
87     }
88
89     // hasToken automatically consumes the next token, if it is a match, and then tabs
90     // if necessary, before inserting the token into the pretty string
91     bool hasToken(const char* token) {
92         size_t i = fIndex;
93         for (size_t j = 0; token[j] && fLength > i; i++, j++) {
94             if (token[j] != fInput[i]) {
95                 return false;
96             }
97         }
98         this->tabString();
99         fIndex = i;
100         fPretty.append(token);
101         fFreshline = false;
102         return true;
103     }
104
105     void parseUntilNewline() {
106         while (fLength > fIndex) {
107             if ('\n' == fInput[fIndex]) {
108                 fIndex++;
109                 this->newline();
110                 break;
111             }
112             fPretty.appendf("%c", fInput[fIndex++]);
113         }
114     }
115
116     // this code assumes it is not actually searching for a newline.  If you need to search for a
117     // newline, then use the function above.  If you do search for a newline with this function
118     // it will consume the entire string and the output will certainly not be prettified
119     void parseUntil(const char* token) {
120         while (fLength > fIndex) {
121             // For embedded newlines,  this code will make sure to embed the newline in the
122             // pretty string, increase the linecount, and tab out the next line to the appropriate
123             // place
124             if ('\n' == fInput[fIndex]) {
125                 this->newline();
126                 this->tabString();
127                 fIndex++;
128             }
129             if (this->hasToken(token)) {
130                 break;
131             }
132             fFreshline = false;
133             fPretty.appendf("%c", fInput[fIndex++]);
134         }
135     }
136
137     // We only tab if on a newline, otherwise consider the line tabbed
138     void tabString() {
139         if (fFreshline) {
140             for (int t = 0; t < fTabs; t++) {
141                 fPretty.append("\t");
142             }
143         }
144     }
145
146     // newline is really a request to add a newline, if we are on a fresh line there is no reason
147     // to add another newline
148     void newline() {
149         if (!fFreshline) {
150             fFreshline = true;
151             fPretty.append("\n");
152             this->lineNumbering();
153         }
154     }
155
156     void lineNumbering() {
157         if (fCountlines) {
158             fPretty.appendf("%4d\t", fLinecount++);
159         }
160     }
161
162     bool fCountlines, fFreshline;
163     int fTabs, fLinecount;
164     size_t fIndex, fLength;
165     SkString fInput, fPretty;
166 };
167
168 SkString PrettyPrintGLSL(const SkString& input, bool countlines) {
169     GLSLPrettyPrint pp;
170     return pp.prettify(input, countlines);
171 }
172
173 } // end namespace