GenerateDocumentation.cpp 25 KB

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