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 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 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. 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 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 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 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 */ 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. 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 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 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 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 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 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 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 309 static void writeHtmlVersionTag(GeneratedFile* file, VersionInfo info, 310 bool addSpacing) { 311 ostringstream stream; 312 if (info.intSize == 32) { 313 stream << "When compiling for 32 bits. "; 314 } else if (info.intSize == 64) { 315 stream << "When compiling for 64 bits. "; 316 } 317 318 if (info.minVersion > 1 || info.maxVersion) { 319 const char* mid = 320 "<a " 321 "href='http://developer.android.com/guide/topics/manifest/" 322 "uses-sdk-element.html#ApiLevels'>API level "; 323 if (info.minVersion <= 1) { 324 // No minimum 325 if (info.maxVersion > 0) { 326 stream << "Removed from " << mid << info.maxVersion + 1 << " and higher"; 327 } 328 } else { 329 if (info.maxVersion == 0) { 330 // No maximum 331 stream << "Added in " << mid << info.minVersion; 332 } else { 333 stream << mid << info.minVersion << " - " << info.maxVersion; 334 } 335 } 336 stream << "</a>"; 337 } 338 string s = stream.str(); 339 // Remove any trailing whitespace 340 while (s.back() == ' ') { 341 s.pop_back(); 342 } 343 if (!s.empty()) { 344 *file << (addSpacing ? " " : "") << s << "\n"; 345 } 346 } 347 348 static void writeDetailedTypeSpecification(GeneratedFile* file, const TypeSpecification* spec) { 349 switch (spec->getKind()) { 350 case SIMPLE: { 351 Type* type = spec->getType(); 352 *file << "<p>A typedef of: " << spec->getSimpleType() 353 << makeAttributeTag(spec->getAttribute(), "", type->getDeprecatedApiLevel(), 354 type->getDeprecatedMessage()) 355 << " "; 356 writeHtmlVersionTag(file, spec->getVersionInfo(), false); 357 *file << "</p>\n"; 358 break; 359 } 360 case RS_OBJECT: { 361 *file << "<p>"; 362 writeHtmlVersionTag(file, spec->getVersionInfo(), false); 363 *file << "</p>\n"; 364 break; 365 } 366 case ENUM: { 367 *file << "<p>An enum with the following values: \n"; 368 writeHtmlVersionTag(file, spec->getVersionInfo(), false); 369 *file << "</p>\n"; 370 371 *file << " <table class='jd-tagtable'><tbody>\n"; 372 const vector<string>& values = spec->getValues(); 373 const vector<string>& valueComments = spec->getValueComments(); 374 for (size_t i = 0; i < values.size(); i++) { 375 *file << " <tr><th>" << values[i] << "</th><td>"; 376 if (valueComments.size() > i) { 377 *file << valueComments[i]; 378 } 379 *file << "</td></tr>\n"; 380 } 381 *file << " </tbody></table><br/>\n"; 382 break; 383 } 384 case STRUCT: { 385 *file << "<p>A structure with the following fields: "; 386 writeHtmlVersionTag(file, spec->getVersionInfo(), false); 387 *file << "</p>\n"; 388 389 *file << " <table class='jd-tagtable'><tbody>\n"; 390 const vector<string>& fields = spec->getFields(); 391 const vector<string>& fieldComments = spec->getFieldComments(); 392 for (size_t i = 0; i < fields.size(); i++) { 393 *file << " <tr><th>" << fields[i] << "</th><td>"; 394 if (fieldComments.size() > i && !fieldComments[i].empty()) { 395 *file << fieldComments[i]; 396 } 397 *file << "</td></tr>\n"; 398 } 399 *file << " </tbody></table><br/>\n"; 400 break; 401 } 402 } 403 } 404 405 static void writeDetailedConstantSpecification(GeneratedFile* file, ConstantSpecification* c) { 406 *file << " <tr><td>"; 407 *file << "Value: " << c->getValue() << "\n"; 408 writeHtmlVersionTag(file, c->getVersionInfo(), true); 409 *file << " </td></tr>\n"; 410 *file << "<br/>\n"; 411 } 412 413 static bool writeOverviewForFile(GeneratedFile* file, const SpecFile& specFile) { 414 bool success = true; 415 *file << "<h2>" << specFile.getBriefDescription() << "</h2>\n"; 416 if (!generateHtmlParagraphs(file, specFile.getFullDescription())) { 417 success = false; 418 } 419 420 // Write the summary tables. 421 // file << "<h2>Summary</h2>\n"; 422 writeSummaryTables(file, specFile.getDocumentedConstants(), specFile.getDocumentedTypes(), 423 specFile.getDocumentedFunctions(), NON_DEPRECATED_ONLY, false); 424 425 return success; 426 } 427 428 static bool generateOverview(const string& directory, bool forVerification) { 429 GeneratedFile file; 430 if (!file.start(directory, forVerification ? OVERVIEW_HTML_FILE_NAME : OVERVIEW_JD_FILE_NAME)) { 431 return false; 432 } 433 bool success = true; 434 435 writeHeader(&file, forVerification, "Runtime API Reference"); 436 437 for (auto specFile : systemSpecification.getSpecFiles()) { 438 if (!writeOverviewForFile(&file, *specFile)) { 439 success = false; 440 } 441 } 442 443 writeFooter(&file, forVerification); 444 file.close(); 445 return success; 446 } 447 448 static bool generateAlphabeticalIndex(const string& directory, bool forVerification) { 449 GeneratedFile file; 450 if (!file.start(directory, forVerification ? INDEX_HTML_FILE_NAME : INDEX_JD_FILE_NAME)) { 451 return false; 452 } 453 writeHeader(&file, forVerification, "Index"); 454 455 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(), 456 systemSpecification.getFunctions(), NON_DEPRECATED_ONLY, true); 457 458 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(), 459 systemSpecification.getFunctions(), DEPRECATED_ONLY, true); 460 461 writeFooter(&file, forVerification); 462 file.close(); 463 return true; 464 } 465 466 static void writeDeprecatedWarning(GeneratedFile* file, Definition* definition) { 467 if (definition->deprecated()) { 468 *file << " <p><b>Deprecated.</b> "; 469 string s = definition->getDeprecatedMessage(); 470 convertDocumentationRefences(&s); 471 if (!s.empty()) { 472 *file << s; 473 } else { 474 *file << "Do not use."; 475 } 476 *file << "</p>\n"; 477 } 478 } 479 480 static bool writeDetailedConstant(GeneratedFile* file, Constant* constant) { 481 if (constant->hidden()) { 482 return true; 483 } 484 const string& name = constant->getName(); 485 486 *file << "<a name='android_rs:" << name << "'></a>\n"; 487 *file << "<div class='jd-details'>\n"; 488 *file << " <h4 class='jd-details-title'>\n"; 489 *file << " <span class='sympad'>" << name << "</span>\n"; 490 *file << " <span class='normal'>: " << constant->getSummary() << "</span>\n"; 491 *file << " </h4>\n"; 492 493 *file << " <div class='jd-details-descr'>\n"; 494 *file << " <table class='jd-tagtable'><tbody>\n"; 495 auto specifications = constant->getSpecifications(); 496 bool addSeparator = specifications.size() > 1; 497 for (auto spec : specifications) { 498 if (addSeparator) { 499 *file << " <h5 class='jd-tagtitle'>Variant:</h5>\n"; 500 } 501 writeDetailedConstantSpecification(file, spec); 502 } 503 *file << " </tbody></table>\n"; 504 *file << " </div>\n"; 505 506 *file << " <div class='jd-tagdata jd-tagdescr'>\n"; 507 508 writeDeprecatedWarning(file, constant); 509 if (!generateHtmlParagraphs(file, constant->getDescription())) { 510 return false; 511 } 512 *file << " </div>\n"; 513 514 *file << "</div>\n"; 515 *file << "\n"; 516 return true; 517 } 518 519 static bool writeDetailedType(GeneratedFile* file, Type* type) { 520 if (type->hidden()) { 521 return true; 522 } 523 const string& name = type->getName(); 524 525 *file << "<a name='android_rs:" << name << "'></a>\n"; 526 *file << "<div class='jd-details'>\n"; 527 *file << " <h4 class='jd-details-title'>\n"; 528 *file << " <span class='sympad'>" << name << "</span>\n"; 529 *file << " <span class='normal'>: " << type->getSummary() << "</span>\n"; 530 *file << " </h4>\n"; 531 532 *file << " <div class='jd-details-descr'>\n"; 533 for (auto spec : type->getSpecifications()) { 534 writeDetailedTypeSpecification(file, spec); 535 } 536 537 writeDeprecatedWarning(file, type); 538 if (!generateHtmlParagraphs(file, type->getDescription())) { 539 return false; 540 } 541 542 *file << " </div>\n"; 543 *file << "</div>\n"; 544 *file << "\n"; 545 return true; 546 } 547 548 static bool writeDetailedFunction(GeneratedFile* file, Function* function) { 549 if (function->hidden()) { 550 return true; 551 } 552 const string& name = function->getName(); 553 554 *file << "<a name='android_rs:" << name << "'></a>\n"; 555 *file << "<div class='jd-details'>\n"; 556 *file << " <h4 class='jd-details-title'>\n"; 557 *file << " <span class='sympad'>" << name << "</span>\n"; 558 *file << " <span class='normal'>: " << function->getSummary() << "</span>\n"; 559 *file << " </h4>\n"; 560 561 *file << " <div class='jd-details-descr'>\n"; 562 map<string, DetailedFunctionEntry> entries; 563 if (!getUnifiedFunctionPrototypes(function, &entries)) { 564 return false; 565 } 566 *file << " <table class='jd-tagtable'><tbody>\n"; 567 for (auto i : entries) { 568 *file << " <tr>\n"; 569 *file << " <td>" << i.second.htmlDeclaration << "</td>\n"; 570 *file << " <td>"; 571 writeHtmlVersionTag(file, i.second.info, true); 572 *file << " </td>\n"; 573 *file << " </tr>\n"; 574 } 575 *file << " </tbody></table>\n"; 576 *file << " </div>\n"; 577 578 if (function->someParametersAreDocumented()) { 579 *file << " <div class='jd-tagdata'>"; 580 *file << " <h5 class='jd-tagtitle'>Parameters</h5>\n"; 581 *file << " <table class='jd-tagtable'><tbody>\n"; 582 for (ParameterEntry* p : function->getParameters()) { 583 *file << " <tr><th>" << p->name << "</th><td>" << p->documentation << "</td></tr>\n"; 584 } 585 *file << " </tbody></table>\n"; 586 *file << " </div>\n"; 587 } 588 589 string ret = function->getReturnDocumentation(); 590 if (!ret.empty()) { 591 *file << " <div class='jd-tagdata'>"; 592 *file << " <h5 class='jd-tagtitle'>Returns</h5>\n"; 593 *file << " <table class='jd-tagtable'><tbody>\n"; 594 *file << " <tr><td>" << ret << "</td></tr>\n"; 595 *file << " </tbody></table>\n"; 596 *file << " </div>\n"; 597 } 598 599 *file << " <div class='jd-tagdata jd-tagdescr'>\n"; 600 writeDeprecatedWarning(file, function); 601 if (!generateHtmlParagraphs(file, function->getDescription())) { 602 return false; 603 } 604 *file << " </div>\n"; 605 606 *file << "</div>\n"; 607 *file << "\n"; 608 return true; 609 } 610 611 static bool writeDetailedDocumentationFile(const string& directory, const SpecFile& specFile, 612 bool forVerification) { 613 if (!specFile.hasSpecifications()) { 614 // This is true for rs_core.spec 615 return true; 616 } 617 618 GeneratedFile file; 619 const string fileName = stringReplace(specFile.getSpecFileName(), ".spec", 620 forVerification ? ".html" : ".jd"); 621 if (!file.start(directory, fileName)) { 622 return false; 623 } 624 bool success = true; 625 626 string title = specFile.getBriefDescription(); 627 writeHeader(&file, forVerification, title); 628 629 file << "<h2>Overview</h2>\n"; 630 if (!generateHtmlParagraphs(&file, specFile.getFullDescription())) { 631 success = false; 632 } 633 634 // Write the summary tables. 635 file << "<h2>Summary</h2>\n"; 636 const auto& constants = specFile.getDocumentedConstants(); 637 const auto& types = specFile.getDocumentedTypes(); 638 const auto& functions = specFile.getDocumentedFunctions(); 639 640 writeSummaryTables(&file, constants, types, functions, NON_DEPRECATED_ONLY, false); 641 writeSummaryTables(&file, constants, types, functions, DEPRECATED_ONLY, false); 642 643 // Write the full details of each constant, type, and function. 644 if (!constants.empty()) { 645 file << "<h2>Constants</h2>\n"; 646 for (auto i : constants) { 647 if (!writeDetailedConstant(&file, i.second)) { 648 success = false; 649 } 650 } 651 } 652 if (!types.empty()) { 653 file << "<h2>Types</h2>\n"; 654 for (auto i : types) { 655 if (!writeDetailedType(&file, i.second)) { 656 success = false; 657 } 658 } 659 } 660 if (!functions.empty()) { 661 file << "<h2>Functions</h2>\n"; 662 for (auto i : functions) { 663 if (!writeDetailedFunction(&file, i.second)) { 664 success = false; 665 } 666 } 667 } 668 669 writeFooter(&file, forVerification); 670 file.close(); 671 672 if (!success) { 673 // If in error, write a final message to make it easier to figure out which file failed. 674 cerr << fileName << ": Failed due to errors.\n"; 675 } 676 return success; 677 } 678 679 static void generateSnippet(GeneratedFile* file, const string& fileName, const string& title) { 680 const char offset[] = " "; 681 *file << offset << "<li><a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/" 682 << fileName << "\">\n"; 683 *file << offset << " <span class=\"en\">" << title << "</span>\n"; 684 *file << offset << "</a></li>\n"; 685 } 686 687 /* Generate a partial file of links that should be cut & pasted into the proper section of the 688 * guide_toc.cs file. 689 */ 690 static bool generateAndroidTableOfContentSnippet(const string& directory) { 691 GeneratedFile file; 692 if (!file.start(directory, "guide_toc.cs")) { 693 return false; 694 } 695 file << "<!-- Copy and paste the following lines into the RenderScript section of\n"; 696 file << " platform/frameworks/base/docs/html/guide/guide_toc.cs\n\n"; 697 698 const char offset[] = " "; 699 file << offset << "<li class=\"nav-section\">\n"; 700 file << offset << " <div class=\"nav-section-header\">\n"; 701 file << offset << " <a href=\"<?cs var:toroot ?>guide/topics/renderscript/reference/" << 702 OVERVIEW_HTML_FILE_NAME << "\">\n"; 703 file << offset << " <span class=\"en\">Runtime API Reference</span>\n"; 704 file << offset << " </a></div>\n"; 705 file << offset << " <ul>\n"; 706 707 for (auto specFile : systemSpecification.getSpecFiles()) { 708 if (specFile->hasSpecifications()) { 709 const string fileName = stringReplace(specFile->getSpecFileName(), ".spec", ".html"); 710 generateSnippet(&file, fileName, specFile->getBriefDescription()); 711 } 712 } 713 generateSnippet(&file, INDEX_HTML_FILE_NAME, "Index"); 714 715 file << offset << " </ul>\n"; 716 file << offset << "</li>\n"; 717 718 return true; 719 } 720 721 bool generateDocumentation(const string& directory, bool forVerification) { 722 bool success = generateOverview(directory, forVerification) && 723 generateAlphabeticalIndex(directory, forVerification) && 724 generateAndroidTableOfContentSnippet(directory); 725 for (auto specFile : systemSpecification.getSpecFiles()) { 726 if (!writeDetailedDocumentationFile(directory, *specFile, forVerification)) { 727 success = false; 728 } 729 } 730 return success; 731 } 732