1 /*
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 
24 using namespace std;
25 
26 struct DetailedFunctionEntry {
27     VersionInfo info;
28     string htmlDeclaration;
29 };
30 
31 static const char OVERVIEW_HTML_FILE_NAME[] = "overview.html";
32 static const char OVERVIEW_JD_FILE_NAME[] = "overview.jd";
33 static const char INDEX_HTML_FILE_NAME[] = "index.html";
34 static const char INDEX_JD_FILE_NAME[] = "index.jd";
35 
writeHeader(GeneratedFile * file,bool forVerification,const string & title)36 static void writeHeader(GeneratedFile* file, bool forVerification, const string& title) {
37     if (forVerification) {
38         *file << "<!DOCTYPE html>\n";
39         *file << "<!-- " << AUTO_GENERATED_WARNING << "-->\n";
40         *file << "<html><head>\n"
41                  "<title>RenderScript Reference</title>\n"
42                  "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
43                  "<link rel='stylesheet' "
44                  "href='http://fonts.googleapis.com/css?family=Roboto+Condensed'>\n"
45                  "<link rel='stylesheet' href='http://fonts.googleapis.com/"
46                  "css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold' "
47                  "title='roboto'>\n"
48                  "<link href='default.css' rel='stylesheet' type='text/css'>\n"
49                  "<link href='fullscreen.css' rel='stylesheet' class='fullscreen' "
50                  "type='text/css'>\n"
51                  "<body class='gc-documentation develop reference'>\n\n";
52         *file << "<h1>" << title << "</h1>\n";
53     } else {
54         *file << "page.title=RenderScript " << title << "\n\n";
55         *file << "@jd:body\n\n";
56     }
57     *file << "<div class='renderscript'>\n";
58 }
59 
writeFooter(GeneratedFile * file,bool forVerification)60 static void writeFooter(GeneratedFile* file, bool forVerification) {
61     *file << "</div>\n";
62     if (forVerification) {
63         *file << "</body></html>\n";
64     }
65 }
66 
67 // If prefix starts input, copy it to stream and remove it from input.
skipPrefix(ostringstream * stream,string * input,const string & prefix)68 static void skipPrefix(ostringstream* stream, string* input, const string& prefix) {
69     size_t size = prefix.size();
70     if (input->compare(0, size, prefix) != 0) {
71         return;
72     }
73     input->erase(0, size);
74     *stream << prefix;
75 }
76 
77 // Merge b into a.  Returns true if successful
mergeVersionInfo(VersionInfo * a,const VersionInfo & b)78 static bool mergeVersionInfo(VersionInfo* a, const VersionInfo& b) {
79     if (a->intSize != b.intSize) {
80         cerr << "Error.  We don't currently support versions that differ based on int size\n";
81         return false;
82     }
83     if (b.minVersion != 0 && a->maxVersion == b.minVersion - 1) {
84         a->maxVersion = b.maxVersion;
85     } else if (b.maxVersion != 0 && a->minVersion == b.maxVersion + 1) {
86         a->minVersion = b.minVersion;
87     } else {
88         cerr << "Error.  This code currently assume that all versions are contiguous.  Don't know "
89                 "how to merge versions (" << a->minVersion << " - " << a->maxVersion << ") and ("
90              << b.minVersion << " - " << b.maxVersion << ")\n";
91         return false;
92     }
93     return true;
94 }
95 
getHtmlStringForType(const ParameterDefinition & parameter)96 static string getHtmlStringForType(const ParameterDefinition& parameter) {
97     string s = parameter.rsType;
98     ostringstream stream;
99     skipPrefix(&stream, &s, "const ");
100     skipPrefix(&stream, &s, "volatile ");
101     bool endsWithAsterisk = s.size() > 0 && s[s.size() - 1] == '*';
102     if (endsWithAsterisk) {
103         s.erase(s.size() - 1, 1);
104     }
105 
106     string anchor = systemSpecification.getHtmlAnchor(s);
107     if (anchor.empty()) {
108         // Not a RenderScript specific type.
109         return parameter.rsType;
110     } else {
111         stream << anchor;
112     }
113     if (endsWithAsterisk) {
114         stream << "*";
115     }
116     return stream.str();
117 }
118 
getDetailedHtmlDeclaration(const FunctionPermutation & permutation)119 static string getDetailedHtmlDeclaration(const FunctionPermutation& permutation) {
120     ostringstream stream;
121     auto ret = permutation.getReturn();
122     if (ret) {
123         stream << getHtmlStringForType(*ret);
124     } else {
125         stream << "void";
126     }
127     stream << " " << permutation.getName() << "(";
128     bool needComma = false;
129     for (auto p : permutation.getParams()) {
130         if (needComma) {
131             stream << ", ";
132         }
133         stream << getHtmlStringForType(*p);
134         if (p->isOutParameter) {
135             stream << "*";
136         }
137         if (!p->specName.empty()) {
138             stream << " " << p->specName;
139         }
140         needComma = true;
141     }
142     stream << ");\n";
143     return stream.str();
144 }
145 
146 /* Some functions (like max) have changed implementations but not their
147  * declaration.  We need to unify these so that we don't end up with entries
148  * like:
149  *   char max(char a, char b);  Removed from API level 20
150  *   char max(char a, char b);  Added to API level 20
151  */
getUnifiedFunctionPrototypes(Function * function,map<string,DetailedFunctionEntry> * entries)152 static bool getUnifiedFunctionPrototypes(Function* function,
153                                          map<string, DetailedFunctionEntry>* entries) {
154     for (auto f : function->getSpecifications()) {
155         DetailedFunctionEntry entry;
156         entry.info = f->getVersionInfo();
157         for (auto p : f->getPermutations()) {
158             entry.htmlDeclaration = getDetailedHtmlDeclaration(*p);
159             const string s = stripHtml(entry.htmlDeclaration);
160             auto i = entries->find(s);
161             if (i == entries->end()) {
162                 entries->insert(pair<string, DetailedFunctionEntry>(s, entry));
163             } else {
164                 if (!mergeVersionInfo(&i->second.info, entry.info)) {
165                     return false;
166                 }
167             }
168         }
169     }
170     return true;
171 }
172 
173 // Convert words starting with @ into HTML references.  Returns false if error.
convertDocumentationRefences(string * s)174 static bool convertDocumentationRefences(string* s) {
175     bool success = true;
176     size_t end = 0;
177     for (;;) {
178         size_t start = s->find('@', end);
179         if (start == string::npos) {
180             break;
181         }
182         // Find the end of the identifier
183         end = start;
184         char c;
185         do {
186             c = (*s)[++end];
187         } while (isalnum(c) || c == '_');
188 
189         const string id = s->substr(start + 1, end - start - 1);
190         string anchor = systemSpecification.getHtmlAnchor(id);
191         if (anchor.empty()) {
192             cerr << "Error:  Can't convert the documentation reference @" << id << "\n";
193             success = false;
194         }
195         s->replace(start, end - start, anchor);
196     }
197     return success;
198 }
199 
generateHtmlParagraphs(GeneratedFile * file,const vector<string> & description)200 static bool generateHtmlParagraphs(GeneratedFile* file, const vector<string>& description) {
201     bool inParagraph = false;
202     for (auto s : description) {
203         // Empty lines in the .spec marks paragraphs.
204         if (s.empty()) {
205             if (inParagraph) {
206                 *file << "</p>\n";
207                 inParagraph = false;
208             }
209         } else {
210             if (!inParagraph) {
211                 *file << "<p> ";
212                 inParagraph = true;
213             }
214         }
215         if (!convertDocumentationRefences(&s)) {
216             return false;
217         }
218         *file << s << "\n";
219     }
220     if (inParagraph) {
221         *file << "</p>\n";
222     }
223     return true;
224 }
225 
writeSummaryTableStart(GeneratedFile * file,const string & label,bool labelIsHeading)226 static void writeSummaryTableStart(GeneratedFile* file, const string& label, bool labelIsHeading) {
227     if (labelIsHeading) {
228         *file << "<h2 style='margin-bottom: 0px;'>" << label << "</h2>\n";
229     }
230     *file << "<table class='jd-sumtable'><tbody>\n";
231     if (!labelIsHeading) {
232         *file << "  <tr><th colspan='2'>" << label << "</th></tr>\n";
233     }
234 }
235 
writeSummaryTableEnd(GeneratedFile * file)236 static void writeSummaryTableEnd(GeneratedFile* file) {
237     *file << "</tbody></table>\n";
238 }
239 
240 enum DeprecatedSelector {
241     DEPRECATED_ONLY,
242     NON_DEPRECATED_ONLY,
243     ALL,
244 };
245 
writeSummaryTableEntry(ostream * stream,Definition * definition,DeprecatedSelector deprecatedSelector)246 static void writeSummaryTableEntry(ostream* stream, Definition* definition,
247                                    DeprecatedSelector deprecatedSelector) {
248     if (definition->hidden()) {
249         return;
250     }
251     const bool deprecated = definition->deprecated();
252     if ((deprecatedSelector == DEPRECATED_ONLY && !deprecated) ||
253         (deprecatedSelector == NON_DEPRECATED_ONLY && deprecated)) {
254         return;
255     }
256 
257     *stream << "  <tr class='alt-color api apilevel-1'>\n";
258     *stream << "    <td class='jd-linkcol'>\n";
259     *stream << "      <a href='" << definition->getUrl() << "'>" << definition->getName()
260             << "</a>\n";
261     *stream << "    </td>\n";
262     *stream << "    <td class='jd-descrcol' width='100%'>\n";
263     *stream << "      ";
264     if (deprecated) {
265         *stream << "<b>Deprecated</b>.  ";
266     }
267     *stream << definition->getSummary() << "\n";
268     *stream << "    </td>\n";
269     *stream << "  </tr>\n";
270 }
271 
writeSummaryTable(GeneratedFile * file,const ostringstream * entries,const char * name,DeprecatedSelector deprecatedSelector,bool labelAsHeader)272 static void writeSummaryTable(GeneratedFile* file, const ostringstream* entries, const char* name,
273                               DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
274     string s = entries->str();
275     if (!s.empty()) {
276         string prefix;
277         if (deprecatedSelector == DEPRECATED_ONLY) {
278             prefix = "Deprecated ";
279         }
280         writeSummaryTableStart(file, prefix + name, labelAsHeader);
281         *file << s;
282         writeSummaryTableEnd(file);
283     }
284 }
285 
writeSummaryTables(GeneratedFile * file,const map<string,Constant * > & constants,const map<string,Type * > & types,const map<string,Function * > & functions,DeprecatedSelector deprecatedSelector,bool labelAsHeader)286 static void writeSummaryTables(GeneratedFile* file, const map<string, Constant*>& constants,
287                                const map<string, Type*>& types,
288                                const map<string, Function*>& functions,
289                                DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
290     ostringstream constantStream;
291     for (auto e : constants) {
292         writeSummaryTableEntry(&constantStream, e.second, deprecatedSelector);
293     }
294     writeSummaryTable(file, &constantStream, "Constants", deprecatedSelector, labelAsHeader);
295 
296     ostringstream typeStream;
297     for (auto e : types) {
298         writeSummaryTableEntry(&typeStream, e.second, deprecatedSelector);
299     }
300     writeSummaryTable(file, &typeStream, "Types", deprecatedSelector, labelAsHeader);
301 
302     ostringstream functionStream;
303     for (auto e : functions) {
304         writeSummaryTableEntry(&functionStream, e.second, deprecatedSelector);
305     }
306     writeSummaryTable(file, &functionStream, "Functions", deprecatedSelector, labelAsHeader);
307 }
308 
writeHtmlVersionTag(GeneratedFile * file,VersionInfo info)309 static void writeHtmlVersionTag(GeneratedFile* file, VersionInfo info) {
310     ostringstream stream;
311     if (info.intSize == 32) {
312         stream << "When compiling for 32 bits. ";
313     } else if (info.intSize == 64) {
314         stream << "When compiling for 64 bits. ";
315     }
316 
317     if (info.minVersion > 1 || info.maxVersion) {
318         const char* mid =
319                     "<a "
320                     "href='http://developer.android.com/guide/topics/manifest/"
321                     "uses-sdk-element.html#ApiLevels'>API level ";
322         if (info.minVersion <= 1) {
323             // No minimum
324             if (info.maxVersion > 0) {
325                 stream << "Removed from " << mid << info.maxVersion + 1 << " and beyond";
326             }
327         } else {
328             if (info.maxVersion == 0) {
329                 // No maximum
330                 stream << "Added in " << mid << info.minVersion;
331             } else {
332                 stream << mid << info.minVersion << " - " << info.maxVersion;
333             }
334         }
335         stream << "</a>";
336     }
337     const string s = stream.str();
338     if (!s.empty()) {
339         *file << "    " << s << "\n";
340     }
341 }
342 
writeDetailedTypeSpecification(GeneratedFile * file,const TypeSpecification * spec)343 static void writeDetailedTypeSpecification(GeneratedFile* file, const TypeSpecification* spec) {
344     switch (spec->getKind()) {
345         case SIMPLE: {
346             Type* type = spec->getType();
347             *file << "<p>A typedef of: " << spec->getSimpleType()
348                   << makeAttributeTag(spec->getAttribute(), "", type->deprecated(),
349                                       type->getDeprecatedMessage())
350                   << "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
351             writeHtmlVersionTag(file, spec->getVersionInfo());
352             *file << "</p>\n";
353             break;
354         }
355         case ENUM: {
356             *file << "<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n";
357             writeHtmlVersionTag(file, spec->getVersionInfo());
358             *file << "</p>\n";
359 
360             *file << "  <table class='jd-tagtable'><tbody>\n";
361             const vector<string>& values = spec->getValues();
362             const vector<string>& valueComments = spec->getValueComments();
363             for (size_t i = 0; i < values.size(); i++) {
364                 *file << "    <tr><th>" << values[i] << "</th><td>";
365                 if (valueComments.size() > i) {
366                     *file << valueComments[i];
367                 }
368                 *file << "</td></tr>\n";
369             }
370             *file << "  </tbody></table><br/>\n";
371             break;
372         }
373         case STRUCT: {
374             *file << "<p>A structure with the following fields:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
375             writeHtmlVersionTag(file, spec->getVersionInfo());
376             *file << "</p>\n";
377 
378             *file << "  <table class='jd-tagtable'><tbody>\n";
379             const vector<string>& fields = spec->getFields();
380             const vector<string>& fieldComments = spec->getFieldComments();
381             for (size_t i = 0; i < fields.size(); i++) {
382                 *file << "    <tr><th>" << fields[i] << "</th><td>";
383                 if (fieldComments.size() > i && !fieldComments[i].empty()) {
384                     *file << fieldComments[i];
385                 }
386                 *file << "</td></tr>\n";
387             }
388             *file << "  </tbody></table><br/>\n";
389             break;
390         }
391     }
392 }
393 
writeDetailedConstantSpecification(GeneratedFile * file,ConstantSpecification * c)394 static void writeDetailedConstantSpecification(GeneratedFile* file, ConstantSpecification* c) {
395     *file << "      <tr><td>";
396     *file << "Value: " << c->getValue() << "\n";
397     writeHtmlVersionTag(file, c->getVersionInfo());
398     *file << "      </td></tr>\n";
399     *file << "<br/>\n";
400 }
401 
writeOverviewForFile(GeneratedFile * file,const SpecFile & specFile)402 static bool writeOverviewForFile(GeneratedFile* file, const SpecFile& specFile) {
403     bool success = true;
404     *file << "<h2>" << specFile.getBriefDescription() << "</h2>\n";
405     if (!generateHtmlParagraphs(file, specFile.getFullDescription())) {
406         success = false;
407     }
408 
409     // Write the summary tables.
410     // file << "<h2>Summary</h2>\n";
411     writeSummaryTables(file, specFile.getDocumentedConstants(), specFile.getDocumentedTypes(),
412                        specFile.getDocumentedFunctions(), NON_DEPRECATED_ONLY, false);
413 
414     return success;
415 }
416 
generateOverview(const string & directory,bool forVerification)417 static bool generateOverview(const string& directory, bool forVerification) {
418     GeneratedFile file;
419     if (!file.start(directory, forVerification ? OVERVIEW_HTML_FILE_NAME : OVERVIEW_JD_FILE_NAME)) {
420         return false;
421     }
422     bool success = true;
423 
424     writeHeader(&file, forVerification, "Runtime API Reference");
425 
426     for (auto specFile : systemSpecification.getSpecFiles()) {
427         if (!writeOverviewForFile(&file, *specFile)) {
428             success = false;
429         }
430     }
431 
432     writeFooter(&file, forVerification);
433     file.close();
434     return success;
435 }
436 
generateAlphabeticalIndex(const string & directory,bool forVerification)437 static bool generateAlphabeticalIndex(const string& directory, bool forVerification) {
438     GeneratedFile file;
439     if (!file.start(directory, forVerification ? INDEX_HTML_FILE_NAME : INDEX_JD_FILE_NAME)) {
440         return false;
441     }
442     writeHeader(&file, forVerification, "Index");
443 
444     writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
445                        systemSpecification.getFunctions(), NON_DEPRECATED_ONLY, true);
446 
447     writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
448                        systemSpecification.getFunctions(), DEPRECATED_ONLY, true);
449 
450     writeFooter(&file, forVerification);
451     file.close();
452     return true;
453 }
454 
writeDeprecatedWarning(GeneratedFile * file,Definition * definition)455 static void writeDeprecatedWarning(GeneratedFile* file, Definition* definition) {
456     if (definition->deprecated()) {
457         *file << "    <p><b>Deprecated.</b>  ";
458         string s = definition->getDeprecatedMessage();
459         convertDocumentationRefences(&s);
460         if (!s.empty()) {
461             *file << s;
462         } else {
463             *file << "Do not use.";
464         }
465         *file << "</p>\n";
466     }
467 }
468 
writeDetailedConstant(GeneratedFile * file,Constant * constant)469 static bool writeDetailedConstant(GeneratedFile* file, Constant* constant) {
470     if (constant->hidden()) {
471         return true;
472     }
473     const string& name = constant->getName();
474 
475     *file << "<a name='android_rs:" << name << "'></a>\n";
476     *file << "<div class='jd-details'>\n";
477     *file << "  <h4 class='jd-details-title'>\n";
478     *file << "    <span class='sympad'>" << name << "</span>\n";
479     *file << "    <span class='normal'>: " << constant->getSummary() << "</span>\n";
480     *file << "  </h4>\n";
481 
482     *file << "  <div class='jd-details-descr'>\n";
483     *file << "    <table class='jd-tagtable'><tbody>\n";
484     auto specifications = constant->getSpecifications();
485     bool addSeparator = specifications.size() > 1;
486     for (auto spec : specifications) {
487         if (addSeparator) {
488             *file << "    <h5 class='jd-tagtitle'>Variant:</h5>\n";
489         }
490         writeDetailedConstantSpecification(file, spec);
491     }
492     *file << "    </tbody></table>\n";
493     *file << "  </div>\n";
494 
495     *file << "    <div class='jd-tagdata jd-tagdescr'>\n";
496 
497     writeDeprecatedWarning(file, constant);
498     if (!generateHtmlParagraphs(file, constant->getDescription())) {
499         return false;
500     }
501     *file << "    </div>\n";
502 
503     *file << "</div>\n";
504     *file << "\n";
505     return true;
506 }
507 
writeDetailedType(GeneratedFile * file,Type * type)508 static bool writeDetailedType(GeneratedFile* file, Type* type) {
509     if (type->hidden()) {
510         return true;
511     }
512     const string& name = type->getName();
513 
514     *file << "<a name='android_rs:" << name << "'></a>\n";
515     *file << "<div class='jd-details'>\n";
516     *file << "  <h4 class='jd-details-title'>\n";
517     *file << "    <span class='sympad'>" << name << "</span>\n";
518     *file << "    <span class='normal'>: " << type->getSummary() << "</span>\n";
519     *file << "  </h4>\n";
520 
521     *file << "  <div class='jd-details-descr'>\n";
522     for (auto spec : type->getSpecifications()) {
523         writeDetailedTypeSpecification(file, spec);
524     }
525 
526     writeDeprecatedWarning(file, type);
527     if (!generateHtmlParagraphs(file, type->getDescription())) {
528         return false;
529     }
530 
531     *file << "  </div>\n";
532     *file << "</div>\n";
533     *file << "\n";
534     return true;
535 }
536 
writeDetailedFunction(GeneratedFile * file,Function * function)537 static bool writeDetailedFunction(GeneratedFile* file, Function* function) {
538     if (function->hidden()) {
539         return true;
540     }
541     const string& name = function->getName();
542 
543     *file << "<a name='android_rs:" << name << "'></a>\n";
544     *file << "<div class='jd-details'>\n";
545     *file << "  <h4 class='jd-details-title'>\n";
546     *file << "    <span class='sympad'>" << name << "</span>\n";
547     *file << "    <span class='normal'>: " << function->getSummary() << "</span>\n";
548     *file << "  </h4>\n";
549 
550     *file << "  <div class='jd-details-descr'>\n";
551     map<string, DetailedFunctionEntry> entries;
552     if (!getUnifiedFunctionPrototypes(function, &entries)) {
553         return false;
554     }
555     *file << "    <table class='jd-tagtable'><tbody>\n";
556     for (auto i : entries) {
557         *file << "      <tr>\n";
558         *file << "        <td>" << i.second.htmlDeclaration << "</td>\n";
559         *file << "        <td>";
560         writeHtmlVersionTag(file, i.second.info);
561         *file << "        </td>\n";
562         *file << "      </tr>\n";
563     }
564     *file << "    </tbody></table>\n";
565     *file << "  </div>\n";
566 
567     if (function->someParametersAreDocumented()) {
568         *file << "  <div class='jd-tagdata'>";
569         *file << "    <h5 class='jd-tagtitle'>Parameters</h5>\n";
570         *file << "    <table class='jd-tagtable'><tbody>\n";
571         for (ParameterEntry* p : function->getParameters()) {
572             *file << "    <tr><th>" << p->name << "</th><td>" << p->documentation << "</td></tr>\n";
573         }
574         *file << "    </tbody></table>\n";
575         *file << "  </div>\n";
576     }
577 
578     string ret = function->getReturnDocumentation();
579     if (!ret.empty()) {
580         *file << "  <div class='jd-tagdata'>";
581         *file << "    <h5 class='jd-tagtitle'>Returns</h5>\n";
582         *file << "    <table class='jd-tagtable'><tbody>\n";
583         *file << "    <tr><td>" << ret << "</td></tr>\n";
584         *file << "    </tbody></table>\n";
585         *file << "  </div>\n";
586     }
587 
588     *file << "  <div class='jd-tagdata jd-tagdescr'>\n";
589     writeDeprecatedWarning(file, function);
590     if (!generateHtmlParagraphs(file, function->getDescription())) {
591         return false;
592     }
593     *file << "  </div>\n";
594 
595     *file << "</div>\n";
596     *file << "\n";
597     return true;
598 }
599 
writeDetailedDocumentationFile(const string & directory,const SpecFile & specFile,bool forVerification)600 static bool writeDetailedDocumentationFile(const string& directory, const SpecFile& specFile,
601                                            bool forVerification) {
602     if (!specFile.hasSpecifications()) {
603         // This is true for rs_core.spec
604         return true;
605     }
606 
607     GeneratedFile file;
608     const string fileName = stringReplace(specFile.getSpecFileName(), ".spec",
609                                           forVerification ? ".html" : ".jd");
610     if (!file.start(directory, fileName)) {
611         return false;
612     }
613     bool success = true;
614 
615     string title = specFile.getBriefDescription();
616     writeHeader(&file, forVerification, title);
617 
618     file << "<h2>Overview</h2>\n";
619     if (!generateHtmlParagraphs(&file, specFile.getFullDescription())) {
620         success = false;
621     }
622 
623     // Write the summary tables.
624     file << "<h2>Summary</h2>\n";
625     const auto& constants = specFile.getDocumentedConstants();
626     const auto& types = specFile.getDocumentedTypes();
627     const auto& functions = specFile.getDocumentedFunctions();
628 
629     writeSummaryTables(&file, constants, types, functions, NON_DEPRECATED_ONLY, false);
630     writeSummaryTables(&file, constants, types, functions, DEPRECATED_ONLY, false);
631 
632     // Write the full details of each constant, type, and function.
633     if (!constants.empty()) {
634         file << "<h2>Constants</h2>\n";
635         for (auto i : constants) {
636             if (!writeDetailedConstant(&file, i.second)) {
637                 success = false;
638             }
639         }
640     }
641     if (!types.empty()) {
642         file << "<h2>Types</h2>\n";
643         for (auto i : types) {
644             if (!writeDetailedType(&file, i.second)) {
645                 success = false;
646             }
647         }
648     }
649     if (!functions.empty()) {
650         file << "<h2>Functions</h2>\n";
651         for (auto i : functions) {
652             if (!writeDetailedFunction(&file, i.second)) {
653                 success = false;
654             }
655         }
656     }
657 
658     writeFooter(&file, forVerification);
659     file.close();
660 
661     if (!success) {
662         // If in error, write a final message to make it easier to figure out which file failed.
663         cerr << fileName << ": Failed due to errors.\n";
664     }
665     return success;
666 }
667 
generateSnippet(GeneratedFile * file,const string & fileName,const string & title)668 static void generateSnippet(GeneratedFile* file, const string& fileName, const string& title) {
669     const char offset[] = "                  ";
670     *file << offset << "<li><a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/"
671           << fileName << "\">\n";
672     *file << offset << "  <span class=\"en\">" << title << "</span>\n";
673     *file << offset << "</a></li>\n";
674 }
675 
676 /* Generate a partial file of links that should be cut & pasted into the proper section of the
677  * guide_toc.cs file.
678  */
generateAndroidTableOfContentSnippet(const string & directory)679 static bool generateAndroidTableOfContentSnippet(const string& directory) {
680     GeneratedFile file;
681     if (!file.start(directory, "guide_toc.cs")) {
682         return false;
683     }
684     file << "<!-- Copy and paste the following lines into the RenderScript section of\n";
685     file << "     platform/frameworks/base/docs/html/guide/guide_toc.cs\n\n";
686 
687     const char offset[] = "              ";
688     file << offset << "<li class=\"nav-section\">\n";
689     file << offset << "  <div class=\"nav-section-header\">\n";
690     file << offset << "    <a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/" <<
691             OVERVIEW_HTML_FILE_NAME << "\">\n";
692     file << offset << "      <span class=\"en\">Runtime API Reference</span>\n";
693     file << offset << "    </a></div>\n";
694     file << offset << "  <ul>\n";
695 
696     for (auto specFile : systemSpecification.getSpecFiles()) {
697         if (specFile->hasSpecifications()) {
698             const string fileName = stringReplace(specFile->getSpecFileName(), ".spec", ".html");
699             generateSnippet(&file, fileName, specFile->getBriefDescription());
700         }
701     }
702     generateSnippet(&file, INDEX_HTML_FILE_NAME, "Index");
703 
704     file << offset << "  </ul>\n";
705     file << offset << "</li>\n";
706 
707     return true;
708 }
709 
generateDocumentation(const string & directory,bool forVerification)710 bool generateDocumentation(const string& directory, bool forVerification) {
711     bool success = generateOverview(directory, forVerification) &&
712                    generateAlphabeticalIndex(directory, forVerification) &&
713                    generateAndroidTableOfContentSnippet(directory);
714     for (auto specFile : systemSpecification.getSpecFiles()) {
715         if (!writeDetailedDocumentationFile(directory, *specFile, forVerification)) {
716             success = false;
717         }
718     }
719     return success;
720 }
721