blob: 94af3110b03e8de3a36eea3d4f7f6bbf958b7c24 [file] [log] [blame]
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -070017#include <algorithm>
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070018#include <iostream>
19#include <sstream>
20
21#include "Generator.h"
22#include "Specification.h"
23#include "Utilities.h"
24
25using namespace std;
26
27struct DetailedFunctionEntry {
28 VersionInfo info;
29 string htmlDeclaration;
30};
31
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -070032static const char OVERVIEW_HTML_FILE_NAME[] = "overview.html";
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -070033static const char INDEX_HTML_FILE_NAME[] = "index.html";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070034
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -070035static void writeHeader(GeneratedFile* file, const string& title,
36 const SpecFile& specFile) {
37 // Generate DevSite markups
38 *file
39 << "<html devsite>\n"
40 "<!-- " << AUTO_GENERATED_WARNING << "-->\n"
41 "<head>\n"
42 " <title>RenderScript " << title << "</title>\n"
43 " <meta name=\"top_category\" value=\"develop\" />\n"
44 " <meta name=\"subcategory\" value=\"guide\" />\n"
45 " <meta name=\"book_path\" value=\"/guide/_book.yaml\" />\n"
46 " <meta name=\"project_path\" value=\"/guide/_project.yaml\" />\n";
47 auto desc = specFile.getFullDescription();
48 if (desc.size()) {
49 *file << " <meta name=\"description\" content=\"";
50 // Output only the first two lines. Assuming there's no other HTML
51 // markups there
52 // TODO: escape/remove markups
I-Jui (Ray) Sung6e6b6562017-11-16 15:46:57 -080053 for (unsigned int i = 0; i < std::min(desc.size(), 2UL); ++i) {
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -070054 if (i) *file << " ";
55 *file << desc[i];
56 }
57 *file << "…\">\n";
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -070058 }
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -070059 *file << "</head>\n\n"
60 "<body>\n\n";
Jean-Luc Brouillet918944e2015-04-30 11:12:40 -070061 *file << "<div class='renderscript'>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070062}
63
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -070064static void writeFooter(GeneratedFile* file) {
Jean-Luc Brouillet918944e2015-04-30 11:12:40 -070065 *file << "</div>\n";
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -070066 *file << "\n\n</body>\n";
67 *file << "</html>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070068}
69
70// If prefix starts input, copy it to stream and remove it from input.
71static void skipPrefix(ostringstream* stream, string* input, const string& prefix) {
72 size_t size = prefix.size();
73 if (input->compare(0, size, prefix) != 0) {
74 return;
75 }
76 input->erase(0, size);
77 *stream << prefix;
78}
79
80// Merge b into a. Returns true if successful
81static bool mergeVersionInfo(VersionInfo* a, const VersionInfo& b) {
82 if (a->intSize != b.intSize) {
83 cerr << "Error. We don't currently support versions that differ based on int size\n";
84 return false;
85 }
86 if (b.minVersion != 0 && a->maxVersion == b.minVersion - 1) {
87 a->maxVersion = b.maxVersion;
88 } else if (b.maxVersion != 0 && a->minVersion == b.maxVersion + 1) {
89 a->minVersion = b.minVersion;
90 } else {
91 cerr << "Error. This code currently assume that all versions are contiguous. Don't know "
92 "how to merge versions (" << a->minVersion << " - " << a->maxVersion << ") and ("
93 << b.minVersion << " - " << b.maxVersion << ")\n";
94 return false;
95 }
96 return true;
97}
98
99static string getHtmlStringForType(const ParameterDefinition& parameter) {
100 string s = parameter.rsType;
101 ostringstream stream;
102 skipPrefix(&stream, &s, "const ");
103 skipPrefix(&stream, &s, "volatile ");
104 bool endsWithAsterisk = s.size() > 0 && s[s.size() - 1] == '*';
105 if (endsWithAsterisk) {
106 s.erase(s.size() - 1, 1);
107 }
108
109 string anchor = systemSpecification.getHtmlAnchor(s);
110 if (anchor.empty()) {
111 // Not a RenderScript specific type.
112 return parameter.rsType;
113 } else {
114 stream << anchor;
115 }
116 if (endsWithAsterisk) {
117 stream << "*";
118 }
119 return stream.str();
120}
121
122static string getDetailedHtmlDeclaration(const FunctionPermutation& permutation) {
123 ostringstream stream;
124 auto ret = permutation.getReturn();
125 if (ret) {
126 stream << getHtmlStringForType(*ret);
127 } else {
128 stream << "void";
129 }
130 stream << " " << permutation.getName() << "(";
131 bool needComma = false;
132 for (auto p : permutation.getParams()) {
133 if (needComma) {
134 stream << ", ";
135 }
136 stream << getHtmlStringForType(*p);
137 if (p->isOutParameter) {
138 stream << "*";
139 }
140 if (!p->specName.empty()) {
141 stream << " " << p->specName;
142 }
143 needComma = true;
144 }
145 stream << ");\n";
146 return stream.str();
147}
148
149/* Some functions (like max) have changed implementations but not their
150 * declaration. We need to unify these so that we don't end up with entries
151 * like:
152 * char max(char a, char b); Removed from API level 20
153 * char max(char a, char b); Added to API level 20
154 */
155static bool getUnifiedFunctionPrototypes(Function* function,
156 map<string, DetailedFunctionEntry>* entries) {
157 for (auto f : function->getSpecifications()) {
158 DetailedFunctionEntry entry;
159 entry.info = f->getVersionInfo();
160 for (auto p : f->getPermutations()) {
161 entry.htmlDeclaration = getDetailedHtmlDeclaration(*p);
162 const string s = stripHtml(entry.htmlDeclaration);
163 auto i = entries->find(s);
164 if (i == entries->end()) {
165 entries->insert(pair<string, DetailedFunctionEntry>(s, entry));
166 } else {
167 if (!mergeVersionInfo(&i->second.info, entry.info)) {
168 return false;
169 }
170 }
171 }
172 }
173 return true;
174}
175
176// Convert words starting with @ into HTML references. Returns false if error.
177static bool convertDocumentationRefences(string* s) {
178 bool success = true;
179 size_t end = 0;
180 for (;;) {
181 size_t start = s->find('@', end);
182 if (start == string::npos) {
183 break;
184 }
185 // Find the end of the identifier
186 end = start;
187 char c;
188 do {
189 c = (*s)[++end];
190 } while (isalnum(c) || c == '_');
191
192 const string id = s->substr(start + 1, end - start - 1);
193 string anchor = systemSpecification.getHtmlAnchor(id);
194 if (anchor.empty()) {
195 cerr << "Error: Can't convert the documentation reference @" << id << "\n";
196 success = false;
197 }
198 s->replace(start, end - start, anchor);
199 }
200 return success;
201}
202
203static bool generateHtmlParagraphs(GeneratedFile* file, const vector<string>& description) {
204 bool inParagraph = false;
205 for (auto s : description) {
206 // Empty lines in the .spec marks paragraphs.
207 if (s.empty()) {
208 if (inParagraph) {
209 *file << "</p>\n";
210 inParagraph = false;
211 }
212 } else {
213 if (!inParagraph) {
214 *file << "<p> ";
215 inParagraph = true;
216 }
217 }
218 if (!convertDocumentationRefences(&s)) {
219 return false;
220 }
221 *file << s << "\n";
222 }
223 if (inParagraph) {
224 *file << "</p>\n";
225 }
226 return true;
227}
228
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700229static void writeSummaryTableStart(GeneratedFile* file, const string& label, bool labelIsHeading) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700230 if (labelIsHeading) {
Jean-Luc Brouillet6386ceb2015-04-28 15:06:30 -0700231 *file << "<h2 style='margin-bottom: 0px;'>" << label << "</h2>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700232 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700233 *file << "<table class='jd-sumtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700234 if (!labelIsHeading) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700235 *file << " <tr><th colspan='2'>" << label << "</th></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700236 }
237}
238
239static void writeSummaryTableEnd(GeneratedFile* file) {
240 *file << "</tbody></table>\n";
241}
242
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700243enum DeprecatedSelector {
244 DEPRECATED_ONLY,
245 NON_DEPRECATED_ONLY,
246 ALL,
247};
248
249static void writeSummaryTableEntry(ostream* stream, Definition* definition,
250 DeprecatedSelector deprecatedSelector) {
251 if (definition->hidden()) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700252 return;
253 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700254 const bool deprecated = definition->deprecated();
255 if ((deprecatedSelector == DEPRECATED_ONLY && !deprecated) ||
256 (deprecatedSelector == NON_DEPRECATED_ONLY && deprecated)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700257 return;
258 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700259
260 *stream << " <tr class='alt-color api apilevel-1'>\n";
261 *stream << " <td class='jd-linkcol'>\n";
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700262 *stream << " <a href='" << definition->getUrl() << "'>" << definition->getName()
263 << "</a>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700264 *stream << " </td>\n";
265 *stream << " <td class='jd-descrcol' width='100%'>\n";
266 *stream << " ";
267 if (deprecated) {
268 *stream << "<b>Deprecated</b>. ";
269 }
270 *stream << definition->getSummary() << "\n";
271 *stream << " </td>\n";
272 *stream << " </tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700273}
274
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700275static void writeSummaryTable(GeneratedFile* file, const ostringstream* entries, const char* name,
276 DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
277 string s = entries->str();
278 if (!s.empty()) {
279 string prefix;
280 if (deprecatedSelector == DEPRECATED_ONLY) {
281 prefix = "Deprecated ";
282 }
283 writeSummaryTableStart(file, prefix + name, labelAsHeader);
284 *file << s;
285 writeSummaryTableEnd(file);
286 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700287}
288
289static void writeSummaryTables(GeneratedFile* file, const map<string, Constant*>& constants,
290 const map<string, Type*>& types,
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700291 const map<string, Function*>& functions,
292 DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
293 ostringstream constantStream;
294 for (auto e : constants) {
295 writeSummaryTableEntry(&constantStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700296 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700297 writeSummaryTable(file, &constantStream, "Constants", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700298
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700299 ostringstream typeStream;
300 for (auto e : types) {
301 writeSummaryTableEntry(&typeStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700302 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700303 writeSummaryTable(file, &typeStream, "Types", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700304
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700305 ostringstream functionStream;
306 for (auto e : functions) {
307 writeSummaryTableEntry(&functionStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700308 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700309 writeSummaryTable(file, &functionStream, "Functions", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700310}
311
Stephen Hinesca51c782015-08-25 23:43:34 -0700312static void writeHtmlVersionTag(GeneratedFile* file, VersionInfo info,
313 bool addSpacing) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700314 ostringstream stream;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700315 if (info.intSize == 32) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700316 stream << "When compiling for 32 bits. ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700317 } else if (info.intSize == 64) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700318 stream << "When compiling for 64 bits. ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700319 }
320
321 if (info.minVersion > 1 || info.maxVersion) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700322 const char* mid =
323 "<a "
324 "href='http://developer.android.com/guide/topics/manifest/"
325 "uses-sdk-element.html#ApiLevels'>API level ";
326 if (info.minVersion <= 1) {
327 // No minimum
328 if (info.maxVersion > 0) {
Jean-Luc Brouilletffc17102015-08-13 22:47:06 -0700329 stream << "Removed from " << mid << info.maxVersion + 1 << " and higher";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700330 }
331 } else {
332 if (info.maxVersion == 0) {
333 // No maximum
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700334 stream << "Added in " << mid << info.minVersion;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700335 } else {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700336 stream << mid << info.minVersion << " - " << info.maxVersion;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700337 }
338 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700339 stream << "</a>";
340 }
Stephen Hinesca51c782015-08-25 23:43:34 -0700341 string s = stream.str();
342 // Remove any trailing whitespace
343 while (s.back() == ' ') {
344 s.pop_back();
345 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700346 if (!s.empty()) {
Stephen Hinesca51c782015-08-25 23:43:34 -0700347 *file << (addSpacing ? " " : "") << s << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700348 }
349}
350
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700351static void writeDetailedTypeSpecification(GeneratedFile* file, const TypeSpecification* spec) {
352 switch (spec->getKind()) {
353 case SIMPLE: {
354 Type* type = spec->getType();
355 *file << "<p>A typedef of: " << spec->getSimpleType()
Stephen Hinesca51c782015-08-25 23:43:34 -0700356 << makeAttributeTag(spec->getAttribute(), "", type->getDeprecatedApiLevel(),
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700357 type->getDeprecatedMessage())
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700358 << "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
Stephen Hinesca51c782015-08-25 23:43:34 -0700359 writeHtmlVersionTag(file, spec->getVersionInfo(), false);
360 *file << "</p>\n";
361 break;
362 }
363 case RS_OBJECT: {
364 *file << "<p>";
365 writeHtmlVersionTag(file, spec->getVersionInfo(), false);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700366 *file << "</p>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700367 break;
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700368 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700369 case ENUM: {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700370 *file << "<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n";
Stephen Hinesca51c782015-08-25 23:43:34 -0700371 writeHtmlVersionTag(file, spec->getVersionInfo(), false);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700372 *file << "</p>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700373
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700374 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700375 const vector<string>& values = spec->getValues();
376 const vector<string>& valueComments = spec->getValueComments();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700377 for (size_t i = 0; i < values.size(); i++) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700378 *file << " <tr><th>" << values[i] << "</th><td>";
379 if (valueComments.size() > i) {
380 *file << valueComments[i];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700381 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700382 *file << "</td></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700383 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700384 *file << " </tbody></table><br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700385 break;
386 }
387 case STRUCT: {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700388 *file << "<p>A structure with the following fields:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
Stephen Hinesca51c782015-08-25 23:43:34 -0700389 writeHtmlVersionTag(file, spec->getVersionInfo(), false);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700390 *file << "</p>\n";
391
392 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouillet36e2be52015-04-30 14:41:24 -0700393 const vector<string>& fields = spec->getFields();
394 const vector<string>& fieldComments = spec->getFieldComments();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700395 for (size_t i = 0; i < fields.size(); i++) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700396 *file << " <tr><th>" << fields[i] << "</th><td>";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700397 if (fieldComments.size() > i && !fieldComments[i].empty()) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700398 *file << fieldComments[i];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700399 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700400 *file << "</td></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700401 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700402 *file << " </tbody></table><br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700403 break;
404 }
405 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700406}
407
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700408static void writeDetailedConstantSpecification(GeneratedFile* file, ConstantSpecification* c) {
409 *file << " <tr><td>";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700410 *file << "Value: " << c->getValue() << "\n";
Stephen Hinesca51c782015-08-25 23:43:34 -0700411 writeHtmlVersionTag(file, c->getVersionInfo(), true);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700412 *file << " </td></tr>\n";
413 *file << "<br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700414}
415
416static bool writeOverviewForFile(GeneratedFile* file, const SpecFile& specFile) {
417 bool success = true;
418 *file << "<h2>" << specFile.getBriefDescription() << "</h2>\n";
419 if (!generateHtmlParagraphs(file, specFile.getFullDescription())) {
420 success = false;
421 }
422
423 // Write the summary tables.
424 // file << "<h2>Summary</h2>\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700425 writeSummaryTables(file, specFile.getDocumentedConstants(), specFile.getDocumentedTypes(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700426 specFile.getDocumentedFunctions(), NON_DEPRECATED_ONLY, false);
427
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700428 return success;
429}
430
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700431static bool generateOverview(const string& directory) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700432 GeneratedFile file;
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700433 if (!file.start(directory, OVERVIEW_HTML_FILE_NAME)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700434 return false;
435 }
436 bool success = true;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700437
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700438 // Take the description from the first spec file (rs_core.spec, based on how
439 // currently this generator is called)
440 writeHeader(&file, "Runtime API Reference",
441 *(systemSpecification.getSpecFiles()[0]));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700442
443 for (auto specFile : systemSpecification.getSpecFiles()) {
444 if (!writeOverviewForFile(&file, *specFile)) {
445 success = false;
446 }
447 }
448
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700449 writeFooter(&file);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700450 file.close();
451 return success;
452}
453
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700454static bool generateAlphabeticalIndex(const string& directory) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700455 GeneratedFile file;
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700456 if (!file.start(directory, INDEX_HTML_FILE_NAME)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700457 return false;
458 }
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700459 writeHeader(&file, "Index", SpecFile(""));
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700460
461 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700462 systemSpecification.getFunctions(), NON_DEPRECATED_ONLY, true);
463
464 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
465 systemSpecification.getFunctions(), DEPRECATED_ONLY, true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700466
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700467 writeFooter(&file);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700468 file.close();
469 return true;
470}
471
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700472static void writeDeprecatedWarning(GeneratedFile* file, Definition* definition) {
473 if (definition->deprecated()) {
474 *file << " <p><b>Deprecated.</b> ";
475 string s = definition->getDeprecatedMessage();
476 convertDocumentationRefences(&s);
477 if (!s.empty()) {
478 *file << s;
479 } else {
480 *file << "Do not use.";
481 }
482 *file << "</p>\n";
483 }
484}
485
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700486static bool writeDetailedConstant(GeneratedFile* file, Constant* constant) {
487 if (constant->hidden()) {
488 return true;
489 }
490 const string& name = constant->getName();
491
Jean-Luc Brouillet918944e2015-04-30 11:12:40 -0700492 *file << "<a name='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700493 *file << "<div class='jd-details'>\n";
494 *file << " <h4 class='jd-details-title'>\n";
495 *file << " <span class='sympad'>" << name << "</span>\n";
496 *file << " <span class='normal'>: " << constant->getSummary() << "</span>\n";
497 *file << " </h4>\n";
498
499 *file << " <div class='jd-details-descr'>\n";
500 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700501 auto specifications = constant->getSpecifications();
502 bool addSeparator = specifications.size() > 1;
503 for (auto spec : specifications) {
504 if (addSeparator) {
505 *file << " <h5 class='jd-tagtitle'>Variant:</h5>\n";
506 }
507 writeDetailedConstantSpecification(file, spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700508 }
509 *file << " </tbody></table>\n";
510 *file << " </div>\n";
511
512 *file << " <div class='jd-tagdata jd-tagdescr'>\n";
513
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700514 writeDeprecatedWarning(file, constant);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700515 if (!generateHtmlParagraphs(file, constant->getDescription())) {
516 return false;
517 }
518 *file << " </div>\n";
519
520 *file << "</div>\n";
521 *file << "\n";
522 return true;
523}
524
525static bool writeDetailedType(GeneratedFile* file, Type* type) {
526 if (type->hidden()) {
527 return true;
528 }
529 const string& name = type->getName();
530
Jean-Luc Brouillet918944e2015-04-30 11:12:40 -0700531 *file << "<a name='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700532 *file << "<div class='jd-details'>\n";
533 *file << " <h4 class='jd-details-title'>\n";
534 *file << " <span class='sympad'>" << name << "</span>\n";
535 *file << " <span class='normal'>: " << type->getSummary() << "</span>\n";
536 *file << " </h4>\n";
537
538 *file << " <div class='jd-details-descr'>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700539 for (auto spec : type->getSpecifications()) {
540 writeDetailedTypeSpecification(file, spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700541 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700542
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700543 writeDeprecatedWarning(file, type);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700544 if (!generateHtmlParagraphs(file, type->getDescription())) {
545 return false;
546 }
547
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700548 *file << " </div>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700549 *file << "</div>\n";
550 *file << "\n";
551 return true;
552}
553
554static bool writeDetailedFunction(GeneratedFile* file, Function* function) {
Jean-Luc Brouillet6386ceb2015-04-28 15:06:30 -0700555 if (function->hidden()) {
556 return true;
557 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700558 const string& name = function->getName();
559
Jean-Luc Brouillet918944e2015-04-30 11:12:40 -0700560 *file << "<a name='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700561 *file << "<div class='jd-details'>\n";
562 *file << " <h4 class='jd-details-title'>\n";
563 *file << " <span class='sympad'>" << name << "</span>\n";
564 *file << " <span class='normal'>: " << function->getSummary() << "</span>\n";
565 *file << " </h4>\n";
566
567 *file << " <div class='jd-details-descr'>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700568 map<string, DetailedFunctionEntry> entries;
569 if (!getUnifiedFunctionPrototypes(function, &entries)) {
570 return false;
571 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700572 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700573 for (auto i : entries) {
574 *file << " <tr>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700575 *file << " <td>" << i.second.htmlDeclaration << "</td>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700576 *file << " <td>";
Stephen Hinesca51c782015-08-25 23:43:34 -0700577 writeHtmlVersionTag(file, i.second.info, true);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700578 *file << " </td>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700579 *file << " </tr>\n";
580 }
581 *file << " </tbody></table>\n";
582 *file << " </div>\n";
583
584 if (function->someParametersAreDocumented()) {
585 *file << " <div class='jd-tagdata'>";
586 *file << " <h5 class='jd-tagtitle'>Parameters</h5>\n";
587 *file << " <table class='jd-tagtable'><tbody>\n";
588 for (ParameterEntry* p : function->getParameters()) {
589 *file << " <tr><th>" << p->name << "</th><td>" << p->documentation << "</td></tr>\n";
590 }
591 *file << " </tbody></table>\n";
592 *file << " </div>\n";
593 }
594
595 string ret = function->getReturnDocumentation();
596 if (!ret.empty()) {
597 *file << " <div class='jd-tagdata'>";
598 *file << " <h5 class='jd-tagtitle'>Returns</h5>\n";
599 *file << " <table class='jd-tagtable'><tbody>\n";
600 *file << " <tr><td>" << ret << "</td></tr>\n";
601 *file << " </tbody></table>\n";
602 *file << " </div>\n";
603 }
604
605 *file << " <div class='jd-tagdata jd-tagdescr'>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700606 writeDeprecatedWarning(file, function);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700607 if (!generateHtmlParagraphs(file, function->getDescription())) {
608 return false;
609 }
610 *file << " </div>\n";
611
612 *file << "</div>\n";
613 *file << "\n";
614 return true;
615}
616
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700617static bool writeDetailedDocumentationFile(const string& directory,
618 const SpecFile& specFile) {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700619 if (!specFile.hasSpecifications()) {
620 // This is true for rs_core.spec
621 return true;
622 }
623
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700624 GeneratedFile file;
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700625 const string fileName = stringReplace(specFile.getSpecFileName(), ".spec",
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700626 ".html");
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700627 if (!file.start(directory, fileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700628 return false;
629 }
630 bool success = true;
631
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700632 string title = specFile.getBriefDescription();
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700633 writeHeader(&file, title, specFile);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700634
635 file << "<h2>Overview</h2>\n";
636 if (!generateHtmlParagraphs(&file, specFile.getFullDescription())) {
637 success = false;
638 }
639
640 // Write the summary tables.
641 file << "<h2>Summary</h2>\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700642 const auto& constants = specFile.getDocumentedConstants();
643 const auto& types = specFile.getDocumentedTypes();
644 const auto& functions = specFile.getDocumentedFunctions();
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700645
646 writeSummaryTables(&file, constants, types, functions, NON_DEPRECATED_ONLY, false);
647 writeSummaryTables(&file, constants, types, functions, DEPRECATED_ONLY, false);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700648
649 // Write the full details of each constant, type, and function.
650 if (!constants.empty()) {
651 file << "<h2>Constants</h2>\n";
652 for (auto i : constants) {
653 if (!writeDetailedConstant(&file, i.second)) {
654 success = false;
655 }
656 }
657 }
658 if (!types.empty()) {
659 file << "<h2>Types</h2>\n";
660 for (auto i : types) {
661 if (!writeDetailedType(&file, i.second)) {
662 success = false;
663 }
664 }
665 }
666 if (!functions.empty()) {
667 file << "<h2>Functions</h2>\n";
668 for (auto i : functions) {
669 if (!writeDetailedFunction(&file, i.second)) {
670 success = false;
671 }
672 }
673 }
674
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700675 writeFooter(&file);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700676 file.close();
677
678 if (!success) {
679 // If in error, write a final message to make it easier to figure out which file failed.
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700680 cerr << fileName << ": Failed due to errors.\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700681 }
682 return success;
683}
684
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700685static void generateSnippet(GeneratedFile* file, const string& fileName, const string& title) {
686 const char offset[] = " ";
687 *file << offset << "<li><a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/"
688 << fileName << "\">\n";
689 *file << offset << " <span class=\"en\">" << title << "</span>\n";
690 *file << offset << "</a></li>\n";
691}
692
693/* Generate a partial file of links that should be cut & pasted into the proper section of the
694 * guide_toc.cs file.
695 */
696static bool generateAndroidTableOfContentSnippet(const string& directory) {
697 GeneratedFile file;
698 if (!file.start(directory, "guide_toc.cs")) {
699 return false;
700 }
701 file << "<!-- Copy and paste the following lines into the RenderScript section of\n";
702 file << " platform/frameworks/base/docs/html/guide/guide_toc.cs\n\n";
703
Jean-Luc Brouillet6386ceb2015-04-28 15:06:30 -0700704 const char offset[] = " ";
705 file << offset << "<li class=\"nav-section\">\n";
706 file << offset << " <div class=\"nav-section-header\">\n";
707 file << offset << " <a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/" <<
708 OVERVIEW_HTML_FILE_NAME << "\">\n";
709 file << offset << " <span class=\"en\">Runtime API Reference</span>\n";
710 file << offset << " </a></div>\n";
711 file << offset << " <ul>\n";
712
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700713 for (auto specFile : systemSpecification.getSpecFiles()) {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700714 if (specFile->hasSpecifications()) {
715 const string fileName = stringReplace(specFile->getSpecFileName(), ".spec", ".html");
716 generateSnippet(&file, fileName, specFile->getBriefDescription());
717 }
718 }
719 generateSnippet(&file, INDEX_HTML_FILE_NAME, "Index");
Jean-Luc Brouillet6386ceb2015-04-28 15:06:30 -0700720
721 file << offset << " </ul>\n";
722 file << offset << "</li>\n";
723
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700724 return true;
725}
726
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700727bool generateDocumentation(const string& directory) {
728 bool success = generateOverview(directory) &&
729 generateAlphabeticalIndex(directory) &&
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700730 generateAndroidTableOfContentSnippet(directory);
731 for (auto specFile : systemSpecification.getSpecFiles()) {
I-Jui (Ray) Sung32d35202017-06-21 13:32:57 -0700732 if (!writeDetailedDocumentationFile(directory, *specFile)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700733 success = false;
734 }
735 }
736 return success;
737}