blob: eab1889ae607bbe276af401673349d7df1074781 [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
17#include <iostream>
18#include <sstream>
19
20#include "Generator.h"
21#include "Specification.h"
22#include "Utilities.h"
23
24using namespace std;
25
26struct DetailedFunctionEntry {
27 VersionInfo info;
28 string htmlDeclaration;
29};
30
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -070031static const char OVERVIEW_HTML_FILE_NAME[] = "overview.html";
32static const char OVERVIEW_JD_FILE_NAME[] = "overview.jd";
33static const char INDEX_HTML_FILE_NAME[] = "index.html";
34static const char INDEX_JD_FILE_NAME[] = "index.jd";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070035
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -070036static void writeHeader(GeneratedFile* file, bool forVerification, const string& title) {
37 if (forVerification) {
38 *file << "<!DOCTYPE html>\n";
39 *file << "<!-- " << AUTO_GENERATED_WARNING << "-->\n";
40
41 *file << "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
42 "<meta name='viewport' content='width=device-width'>\n"
43 "<link rel='shortcut icon' type='image/x-icon' "
44 "href='http://developer.android.com/favicon.ico'>\n"
45 "<title>android.renderscript | Android Developers</title>\n"
46 "<!-- STYLESHEETS -->\n"
47 "<link rel='stylesheet' "
48 "href='http://fonts.googleapis.com/css?family=Roboto+Condensed'>\n"
49 "<link rel='stylesheet' href='http://fonts.googleapis.com/"
50 "css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold' "
51 "title='roboto'>\n"
52 "<link href='./test_files/default.css' rel='stylesheet' type='text/css'>\n"
53 "<!-- FULLSCREEN STYLESHEET -->\n"
54 "<link href='./test_files/fullscreen.css' rel='stylesheet' class='fullscreen' "
55 "type='text/css'>\n"
56 "<!-- JAVASCRIPT -->\n"
57 "<script src='./test_files/cb=gapi.loaded_0' async=''></script><script "
58 "type='text/javascript' async='' src='./test_files/plusone.js' "
59 "gapi_processed='true'></script><script async='' "
60 "src='./test_files/analytics.js'></script><script src='./test_files/jsapi' "
61 "type='text/javascript'></script>\n"
62 "<script src='./test_files/android_3p-bundle.js' "
63 "type='text/javascript'></script>\n"
64 "<script type='text/javascript'>\n"
65 " var toRoot = '/';\n"
66 " var metaTags = [];\n"
67 " var devsite = false;\n"
68 "</script>\n"
69 "<script src='./test_files/docs.js' type='text/javascript'></script><script "
70 "type='text/javascript' src='./test_files/saved_resource'></script>\n"
71 "<script>\n"
72 " (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n"
73 " (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new "
74 "Date();a=s.createElement(o),\n"
75 " "
76 "m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n"
77 " })(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n"
78 " ga('create', 'UA-5831155-1', 'android.com');\n"
79 " ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'}); // New "
80 "tracker);\n"
81 " ga('send', 'pageview');\n"
82 " ga('universal.send', 'pageview'); // Send page view for new tracker.\n"
83 "</script>\n"
84 "<link type='text/css' href='./test_files/default+en.css' "
85 "rel='stylesheet'><script "
86 "type='text/javascript' src='./test_files/default+en.I.js'></script></head>\n"
87 "<body class='gc-documentation\n"
88 " develop reference'>\n\n";
89 *file << "<h1>" << title << "</h1>\n";
90 } else {
91 *file << "page.title=RenderScript " << title << "\n\n";
92 *file << "@jd:body\n\n";
93 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070094}
95
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -070096static void writeFooter(GeneratedFile* file, bool forVerification) {
97 if (forVerification) {
98 *file << "<!-- end body-content -->\n</body></html>\n";
99 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700100}
101
102// If prefix starts input, copy it to stream and remove it from input.
103static void skipPrefix(ostringstream* stream, string* input, const string& prefix) {
104 size_t size = prefix.size();
105 if (input->compare(0, size, prefix) != 0) {
106 return;
107 }
108 input->erase(0, size);
109 *stream << prefix;
110}
111
112// Merge b into a. Returns true if successful
113static bool mergeVersionInfo(VersionInfo* a, const VersionInfo& b) {
114 if (a->intSize != b.intSize) {
115 cerr << "Error. We don't currently support versions that differ based on int size\n";
116 return false;
117 }
118 if (b.minVersion != 0 && a->maxVersion == b.minVersion - 1) {
119 a->maxVersion = b.maxVersion;
120 } else if (b.maxVersion != 0 && a->minVersion == b.maxVersion + 1) {
121 a->minVersion = b.minVersion;
122 } else {
123 cerr << "Error. This code currently assume that all versions are contiguous. Don't know "
124 "how to merge versions (" << a->minVersion << " - " << a->maxVersion << ") and ("
125 << b.minVersion << " - " << b.maxVersion << ")\n";
126 return false;
127 }
128 return true;
129}
130
131static string getHtmlStringForType(const ParameterDefinition& parameter) {
132 string s = parameter.rsType;
133 ostringstream stream;
134 skipPrefix(&stream, &s, "const ");
135 skipPrefix(&stream, &s, "volatile ");
136 bool endsWithAsterisk = s.size() > 0 && s[s.size() - 1] == '*';
137 if (endsWithAsterisk) {
138 s.erase(s.size() - 1, 1);
139 }
140
141 string anchor = systemSpecification.getHtmlAnchor(s);
142 if (anchor.empty()) {
143 // Not a RenderScript specific type.
144 return parameter.rsType;
145 } else {
146 stream << anchor;
147 }
148 if (endsWithAsterisk) {
149 stream << "*";
150 }
151 return stream.str();
152}
153
154static string getDetailedHtmlDeclaration(const FunctionPermutation& permutation) {
155 ostringstream stream;
156 auto ret = permutation.getReturn();
157 if (ret) {
158 stream << getHtmlStringForType(*ret);
159 } else {
160 stream << "void";
161 }
162 stream << " " << permutation.getName() << "(";
163 bool needComma = false;
164 for (auto p : permutation.getParams()) {
165 if (needComma) {
166 stream << ", ";
167 }
168 stream << getHtmlStringForType(*p);
169 if (p->isOutParameter) {
170 stream << "*";
171 }
172 if (!p->specName.empty()) {
173 stream << " " << p->specName;
174 }
175 needComma = true;
176 }
177 stream << ");\n";
178 return stream.str();
179}
180
181/* Some functions (like max) have changed implementations but not their
182 * declaration. We need to unify these so that we don't end up with entries
183 * like:
184 * char max(char a, char b); Removed from API level 20
185 * char max(char a, char b); Added to API level 20
186 */
187static bool getUnifiedFunctionPrototypes(Function* function,
188 map<string, DetailedFunctionEntry>* entries) {
189 for (auto f : function->getSpecifications()) {
190 DetailedFunctionEntry entry;
191 entry.info = f->getVersionInfo();
192 for (auto p : f->getPermutations()) {
193 entry.htmlDeclaration = getDetailedHtmlDeclaration(*p);
194 const string s = stripHtml(entry.htmlDeclaration);
195 auto i = entries->find(s);
196 if (i == entries->end()) {
197 entries->insert(pair<string, DetailedFunctionEntry>(s, entry));
198 } else {
199 if (!mergeVersionInfo(&i->second.info, entry.info)) {
200 return false;
201 }
202 }
203 }
204 }
205 return true;
206}
207
208// Convert words starting with @ into HTML references. Returns false if error.
209static bool convertDocumentationRefences(string* s) {
210 bool success = true;
211 size_t end = 0;
212 for (;;) {
213 size_t start = s->find('@', end);
214 if (start == string::npos) {
215 break;
216 }
217 // Find the end of the identifier
218 end = start;
219 char c;
220 do {
221 c = (*s)[++end];
222 } while (isalnum(c) || c == '_');
223
224 const string id = s->substr(start + 1, end - start - 1);
225 string anchor = systemSpecification.getHtmlAnchor(id);
226 if (anchor.empty()) {
227 cerr << "Error: Can't convert the documentation reference @" << id << "\n";
228 success = false;
229 }
230 s->replace(start, end - start, anchor);
231 }
232 return success;
233}
234
235static bool generateHtmlParagraphs(GeneratedFile* file, const vector<string>& description) {
236 bool inParagraph = false;
237 for (auto s : description) {
238 // Empty lines in the .spec marks paragraphs.
239 if (s.empty()) {
240 if (inParagraph) {
241 *file << "</p>\n";
242 inParagraph = false;
243 }
244 } else {
245 if (!inParagraph) {
246 *file << "<p> ";
247 inParagraph = true;
248 }
249 }
250 if (!convertDocumentationRefences(&s)) {
251 return false;
252 }
253 *file << s << "\n";
254 }
255 if (inParagraph) {
256 *file << "</p>\n";
257 }
258 return true;
259}
260
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700261static void writeSummaryTableStart(GeneratedFile* file, const string& label, bool labelIsHeading) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700262 if (labelIsHeading) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700263 *file << "<h2 style='margin-bottom: 0px;'>" << label << "</h2><hr/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700264 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700265 *file << "<table class='jd-sumtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700266 if (!labelIsHeading) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700267 *file << " <tr><th colspan='2'>" << label << "</th></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700268 }
269}
270
271static void writeSummaryTableEnd(GeneratedFile* file) {
272 *file << "</tbody></table>\n";
273}
274
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700275enum DeprecatedSelector {
276 DEPRECATED_ONLY,
277 NON_DEPRECATED_ONLY,
278 ALL,
279};
280
281static void writeSummaryTableEntry(ostream* stream, Definition* definition,
282 DeprecatedSelector deprecatedSelector) {
283 if (definition->hidden()) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700284 return;
285 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700286 const bool deprecated = definition->deprecated();
287 if ((deprecatedSelector == DEPRECATED_ONLY && !deprecated) ||
288 (deprecatedSelector == NON_DEPRECATED_ONLY && deprecated)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700289 return;
290 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700291
292 *stream << " <tr class='alt-color api apilevel-1'>\n";
293 *stream << " <td class='jd-linkcol'>\n";
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700294 *stream << " <a href='" << definition->getUrl() << "'>" << definition->getName()
295 << "</a>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700296 *stream << " </td>\n";
297 *stream << " <td class='jd-descrcol' width='100%'>\n";
298 *stream << " ";
299 if (deprecated) {
300 *stream << "<b>Deprecated</b>. ";
301 }
302 *stream << definition->getSummary() << "\n";
303 *stream << " </td>\n";
304 *stream << " </tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700305}
306
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700307static void writeSummaryTable(GeneratedFile* file, const ostringstream* entries, const char* name,
308 DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
309 string s = entries->str();
310 if (!s.empty()) {
311 string prefix;
312 if (deprecatedSelector == DEPRECATED_ONLY) {
313 prefix = "Deprecated ";
314 }
315 writeSummaryTableStart(file, prefix + name, labelAsHeader);
316 *file << s;
317 writeSummaryTableEnd(file);
318 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700319}
320
321static void writeSummaryTables(GeneratedFile* file, const map<string, Constant*>& constants,
322 const map<string, Type*>& types,
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700323 const map<string, Function*>& functions,
324 DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
325 ostringstream constantStream;
326 for (auto e : constants) {
327 writeSummaryTableEntry(&constantStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700328 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700329 writeSummaryTable(file, &constantStream, "Constants", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700330
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700331 ostringstream typeStream;
332 for (auto e : types) {
333 writeSummaryTableEntry(&typeStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700334 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700335 writeSummaryTable(file, &typeStream, "Types", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700336
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700337 ostringstream functionStream;
338 for (auto e : functions) {
339 writeSummaryTableEntry(&functionStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700340 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700341 writeSummaryTable(file, &functionStream, "Functions", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700342}
343
344static void writeHtmlVersionTag(GeneratedFile* file, VersionInfo info) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700345 ostringstream stream;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700346 if (info.intSize == 32) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700347 stream << "When compiling for 32 bits. ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700348 } else if (info.intSize == 64) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700349 stream << "When compiling for 64 bits. ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700350 }
351
352 if (info.minVersion > 1 || info.maxVersion) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700353 const char* mid =
354 "<a "
355 "href='http://developer.android.com/guide/topics/manifest/"
356 "uses-sdk-element.html#ApiLevels'>API level ";
357 if (info.minVersion <= 1) {
358 // No minimum
359 if (info.maxVersion > 0) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700360 stream << "Removed from " << mid << info.maxVersion + 1;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700361 }
362 } else {
363 if (info.maxVersion == 0) {
364 // No maximum
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700365 stream << "Added in " << mid << info.minVersion;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700366 } else {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700367 stream << mid << info.minVersion << " - " << info.maxVersion;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700368 }
369 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700370 stream << "</a>";
371 }
372 const string s = stream.str();
373 if (!s.empty()) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700374 *file << " " << s << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700375 }
376}
377
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700378static void writeDetailedTypeSpecification(GeneratedFile* file, const TypeSpecification* type) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700379 switch (type->getKind()) {
380 case SIMPLE:
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700381 *file << "<p>A typedef of: " << type->getSimpleType()
382 << "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
383 writeHtmlVersionTag(file, type->getVersionInfo());
384 *file << "</p>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700385 break;
386 case ENUM: {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700387 *file << "<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n";
388 writeHtmlVersionTag(file, type->getVersionInfo());
389 *file << "</p>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700390
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700391 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700392 const vector<string>& values = type->getValues();
393 const vector<string>& valueComments = type->getValueComments();
394 for (size_t i = 0; i < values.size(); i++) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700395 *file << " <tr><th>" << values[i] << "</th><td>";
396 if (valueComments.size() > i) {
397 *file << valueComments[i];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700398 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700399 *file << "</td></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700400 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700401 *file << " </tbody></table><br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700402 break;
403 }
404 case STRUCT: {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700405 *file << "<p>A structure with the following fields:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
406 writeHtmlVersionTag(file, type->getVersionInfo());
407 *file << "</p>\n";
408
409 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700410 const vector<string>& fields = type->getFields();
411 const vector<string>& fieldComments = type->getFieldComments();
412 for (size_t i = 0; i < fields.size(); i++) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700413 *file << " <tr><th>" << fields[i] << "</th><td>";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700414 if (fieldComments.size() > i && !fieldComments[i].empty()) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700415 *file << fieldComments[i];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700416 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700417 *file << "</td></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700418 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700419 *file << " </tbody></table><br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700420 break;
421 }
422 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700423}
424
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700425static void writeDetailedConstantSpecification(GeneratedFile* file, ConstantSpecification* c) {
426 *file << " <tr><td>";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700427 *file << "Value: " << c->getValue() << "\n";
428 writeHtmlVersionTag(file, c->getVersionInfo());
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700429 *file << " </td></tr>\n";
430 *file << "<br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700431}
432
433static bool writeOverviewForFile(GeneratedFile* file, const SpecFile& specFile) {
434 bool success = true;
435 *file << "<h2>" << specFile.getBriefDescription() << "</h2>\n";
436 if (!generateHtmlParagraphs(file, specFile.getFullDescription())) {
437 success = false;
438 }
439
440 // Write the summary tables.
441 // file << "<h2>Summary</h2>\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700442 writeSummaryTables(file, specFile.getDocumentedConstants(), specFile.getDocumentedTypes(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700443 specFile.getDocumentedFunctions(), NON_DEPRECATED_ONLY, false);
444
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700445 return success;
446}
447
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700448static bool generateOverview(const string& directory, bool forVerification) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700449 GeneratedFile file;
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700450 if (!file.start(directory, forVerification ? OVERVIEW_HTML_FILE_NAME : OVERVIEW_JD_FILE_NAME)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700451 return false;
452 }
453 bool success = true;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700454
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700455 writeHeader(&file, forVerification, "Overview");
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700456
457 for (auto specFile : systemSpecification.getSpecFiles()) {
458 if (!writeOverviewForFile(&file, *specFile)) {
459 success = false;
460 }
461 }
462
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700463 writeFooter(&file, forVerification);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700464 file.close();
465 return success;
466}
467
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700468static bool generateAlphabeticalIndex(const string& directory, bool forVerification) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700469 GeneratedFile file;
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700470 if (!file.start(directory, forVerification ? INDEX_HTML_FILE_NAME : INDEX_JD_FILE_NAME)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700471 return false;
472 }
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700473 writeHeader(&file, forVerification, "Index");
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700474
475 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700476 systemSpecification.getFunctions(), NON_DEPRECATED_ONLY, true);
477
478 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
479 systemSpecification.getFunctions(), DEPRECATED_ONLY, true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700480
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700481 writeFooter(&file, forVerification);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700482 file.close();
483 return true;
484}
485
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700486static void writeDeprecatedWarning(GeneratedFile* file, Definition* definition) {
487 if (definition->deprecated()) {
488 *file << " <p><b>Deprecated.</b> ";
489 string s = definition->getDeprecatedMessage();
490 convertDocumentationRefences(&s);
491 if (!s.empty()) {
492 *file << s;
493 } else {
494 *file << "Do not use.";
495 }
496 *file << "</p>\n";
497 }
498}
499
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700500static bool writeDetailedConstant(GeneratedFile* file, Constant* constant) {
501 if (constant->hidden()) {
502 return true;
503 }
504 const string& name = constant->getName();
505
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700506 *file << "<a id='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700507 *file << "<div class='jd-details'>\n";
508 *file << " <h4 class='jd-details-title'>\n";
509 *file << " <span class='sympad'>" << name << "</span>\n";
510 *file << " <span class='normal'>: " << constant->getSummary() << "</span>\n";
511 *file << " </h4>\n";
512
513 *file << " <div class='jd-details-descr'>\n";
514 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700515 auto specifications = constant->getSpecifications();
516 bool addSeparator = specifications.size() > 1;
517 for (auto spec : specifications) {
518 if (addSeparator) {
519 *file << " <h5 class='jd-tagtitle'>Variant:</h5>\n";
520 }
521 writeDetailedConstantSpecification(file, spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700522 }
523 *file << " </tbody></table>\n";
524 *file << " </div>\n";
525
526 *file << " <div class='jd-tagdata jd-tagdescr'>\n";
527
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700528 writeDeprecatedWarning(file, constant);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700529 if (!generateHtmlParagraphs(file, constant->getDescription())) {
530 return false;
531 }
532 *file << " </div>\n";
533
534 *file << "</div>\n";
535 *file << "\n";
536 return true;
537}
538
539static bool writeDetailedType(GeneratedFile* file, Type* type) {
540 if (type->hidden()) {
541 return true;
542 }
543 const string& name = type->getName();
544
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700545 *file << "<a id='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700546 *file << "<div class='jd-details'>\n";
547 *file << " <h4 class='jd-details-title'>\n";
548 *file << " <span class='sympad'>" << name << "</span>\n";
549 *file << " <span class='normal'>: " << type->getSummary() << "</span>\n";
550 *file << " </h4>\n";
551
552 *file << " <div class='jd-details-descr'>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700553 for (auto spec : type->getSpecifications()) {
554 writeDetailedTypeSpecification(file, spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700555 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700556
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700557 writeDeprecatedWarning(file, type);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700558 if (!generateHtmlParagraphs(file, type->getDescription())) {
559 return false;
560 }
561
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700562 *file << " </div>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700563 *file << "</div>\n";
564 *file << "\n";
565 return true;
566}
567
568static bool writeDetailedFunction(GeneratedFile* file, Function* function) {
569 const string& name = function->getName();
570
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700571 *file << "<a id='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700572 *file << "<div class='jd-details'>\n";
573 *file << " <h4 class='jd-details-title'>\n";
574 *file << " <span class='sympad'>" << name << "</span>\n";
575 *file << " <span class='normal'>: " << function->getSummary() << "</span>\n";
576 *file << " </h4>\n";
577
578 *file << " <div class='jd-details-descr'>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700579 map<string, DetailedFunctionEntry> entries;
580 if (!getUnifiedFunctionPrototypes(function, &entries)) {
581 return false;
582 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700583 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700584 for (auto i : entries) {
585 *file << " <tr>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700586 *file << " <td>" << i.second.htmlDeclaration << "</td>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700587 *file << " <td>";
588 writeHtmlVersionTag(file, i.second.info);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700589 *file << " </td>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700590 *file << " </tr>\n";
591 }
592 *file << " </tbody></table>\n";
593 *file << " </div>\n";
594
595 if (function->someParametersAreDocumented()) {
596 *file << " <div class='jd-tagdata'>";
597 *file << " <h5 class='jd-tagtitle'>Parameters</h5>\n";
598 *file << " <table class='jd-tagtable'><tbody>\n";
599 for (ParameterEntry* p : function->getParameters()) {
600 *file << " <tr><th>" << p->name << "</th><td>" << p->documentation << "</td></tr>\n";
601 }
602 *file << " </tbody></table>\n";
603 *file << " </div>\n";
604 }
605
606 string ret = function->getReturnDocumentation();
607 if (!ret.empty()) {
608 *file << " <div class='jd-tagdata'>";
609 *file << " <h5 class='jd-tagtitle'>Returns</h5>\n";
610 *file << " <table class='jd-tagtable'><tbody>\n";
611 *file << " <tr><td>" << ret << "</td></tr>\n";
612 *file << " </tbody></table>\n";
613 *file << " </div>\n";
614 }
615
616 *file << " <div class='jd-tagdata jd-tagdescr'>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700617 writeDeprecatedWarning(file, function);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700618 if (!generateHtmlParagraphs(file, function->getDescription())) {
619 return false;
620 }
621 *file << " </div>\n";
622
623 *file << "</div>\n";
624 *file << "\n";
625 return true;
626}
627
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700628static bool writeDetailedDocumentationFile(const string& directory, const SpecFile& specFile,
629 bool forVerification) {
630 if (!specFile.hasSpecifications()) {
631 // This is true for rs_core.spec
632 return true;
633 }
634
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700635 GeneratedFile file;
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700636 const string fileName = stringReplace(specFile.getSpecFileName(), ".spec",
637 forVerification ? ".html" : ".jd");
638 if (!file.start(directory, fileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700639 return false;
640 }
641 bool success = true;
642
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700643 string title = specFile.getBriefDescription();
644 writeHeader(&file, forVerification, title);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700645
646 file << "<h2>Overview</h2>\n";
647 if (!generateHtmlParagraphs(&file, specFile.getFullDescription())) {
648 success = false;
649 }
650
651 // Write the summary tables.
652 file << "<h2>Summary</h2>\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700653 const auto& constants = specFile.getDocumentedConstants();
654 const auto& types = specFile.getDocumentedTypes();
655 const auto& functions = specFile.getDocumentedFunctions();
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700656
657 writeSummaryTables(&file, constants, types, functions, NON_DEPRECATED_ONLY, false);
658 writeSummaryTables(&file, constants, types, functions, DEPRECATED_ONLY, false);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700659
660 // Write the full details of each constant, type, and function.
661 if (!constants.empty()) {
662 file << "<h2>Constants</h2>\n";
663 for (auto i : constants) {
664 if (!writeDetailedConstant(&file, i.second)) {
665 success = false;
666 }
667 }
668 }
669 if (!types.empty()) {
670 file << "<h2>Types</h2>\n";
671 for (auto i : types) {
672 if (!writeDetailedType(&file, i.second)) {
673 success = false;
674 }
675 }
676 }
677 if (!functions.empty()) {
678 file << "<h2>Functions</h2>\n";
679 for (auto i : functions) {
680 if (!writeDetailedFunction(&file, i.second)) {
681 success = false;
682 }
683 }
684 }
685
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700686 writeFooter(&file, forVerification);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700687 file.close();
688
689 if (!success) {
690 // 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 -0700691 cerr << fileName << ": Failed due to errors.\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700692 }
693 return success;
694}
695
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700696static void generateSnippet(GeneratedFile* file, const string& fileName, const string& title) {
697 const char offset[] = " ";
698 *file << offset << "<li><a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/"
699 << fileName << "\">\n";
700 *file << offset << " <span class=\"en\">" << title << "</span>\n";
701 *file << offset << "</a></li>\n";
702}
703
704/* Generate a partial file of links that should be cut & pasted into the proper section of the
705 * guide_toc.cs file.
706 */
707static bool generateAndroidTableOfContentSnippet(const string& directory) {
708 GeneratedFile file;
709 if (!file.start(directory, "guide_toc.cs")) {
710 return false;
711 }
712 file << "<!-- Copy and paste the following lines into the RenderScript section of\n";
713 file << " platform/frameworks/base/docs/html/guide/guide_toc.cs\n\n";
714
715 generateSnippet(&file, OVERVIEW_HTML_FILE_NAME, "Overview");
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700716 for (auto specFile : systemSpecification.getSpecFiles()) {
Jean-Luc Brouillet2217eb72015-04-24 14:41:48 -0700717 if (specFile->hasSpecifications()) {
718 const string fileName = stringReplace(specFile->getSpecFileName(), ".spec", ".html");
719 generateSnippet(&file, fileName, specFile->getBriefDescription());
720 }
721 }
722 generateSnippet(&file, INDEX_HTML_FILE_NAME, "Index");
723 return true;
724}
725
726bool generateDocumentation(const string& directory, bool forVerification) {
727 bool success = generateOverview(directory, forVerification) &&
728 generateAlphabeticalIndex(directory, forVerification) &&
729 generateAndroidTableOfContentSnippet(directory);
730 for (auto specFile : systemSpecification.getSpecFiles()) {
731 if (!writeDetailedDocumentationFile(directory, *specFile, forVerification)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700732 success = false;
733 }
734 }
735 return success;
736}