new batch of docs

new batch of docs

Docs-Preview: https://skia.org/?cl=141244
Bug: skia:
Change-Id: I5a285778baaee2734495374adeb7359d524e47e3
Reviewed-on: https://skia-review.googlesource.com/141244
Reviewed-by: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index 1b8e76e..c173c09 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -51,6 +51,8 @@
      would rather keep links for body above #Literal, and/or make it a block and not a one-liner
 add check to require #Const to contain #Code block if defining const or constexpr (enum consts have
      #Code blocks inside the #Enum def)
+subclasses (e.g. Iter in SkPath) need to check for #Line and generate overview
+     subclass methods should also disallow #In
 
 There are a number of formatting bugs with ad hoc patches where a substitution doesn't keep
 the space before or after, or the linefeeds before or after. The rules are not very good either.
diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h
index 19ea86b..04b1c0f 100644
--- a/tools/bookmaker/bookmaker.h
+++ b/tools/bookmaker/bookmaker.h
@@ -42,6 +42,7 @@
     kNone,
     kSK_API,
     kSK_BEGIN_REQUIRE_DENSE,
+    kAlignAs,
     kBool,
     kChar,
     kClass,
@@ -1568,6 +1569,7 @@
         fIncludeWord = nullptr;
     }
 
+    bool inAlignAs() const;
     void checkForMissingParams(const vector<string>& methodParams,
                                const vector<string>& foundParams);
     bool checkForWord();
@@ -1580,11 +1582,13 @@
     void dumpConst(const Definition& , string className);
     void dumpDefine(const Definition& );
     void dumpEnum(const Definition& , string name);
-    bool dumpGlobals();
+    bool dumpGlobals(string* globalFileName, long int* globalTell);
     void dumpMethod(const Definition& , string className);
     void dumpMember(const Definition& );
     bool dumpTokens();
-    bool dumpTokens(string skClassName);
+    bool dumpTokens(string skClassName, string globalFileName, long int* globalTell);
+    void dumpTypedef(const Definition& , string className);
+
     bool findComments(const Definition& includeDef, Definition* markupDef);
     Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
                                   string typeName);
@@ -1593,6 +1597,7 @@
     bool isClone(const Definition& token);
     bool isConstructor(const Definition& token, string className);
     bool isInternalName(const Definition& token);
+    bool isMember(const Definition& token) const;
     bool isOperator(const Definition& token);
     Definition* parentBracket(Definition* parent) const;
     bool parseChar();
diff --git a/tools/bookmaker/definition.cpp b/tools/bookmaker/definition.cpp
index 4dfeda3..fa32b7a 100644
--- a/tools/bookmaker/definition.cpp
+++ b/tools/bookmaker/definition.cpp
@@ -339,7 +339,7 @@
 // for now, just handle paint -- maybe fiddle will loosen naming restrictions
 void Definition::setCanonicalFiddle() {
     fMethodType = Definition::MethodType::kNone;
-    size_t doubleColons = fName.find("::", 0);
+    size_t doubleColons = fName.rfind("::");
     SkASSERT(string::npos != doubleColons);
     string base = fName.substr(0, doubleColons);
     string result = base + "_";
@@ -535,6 +535,7 @@
     const char* descEnd = nullptr;
     const Definition* defEnd = nullptr;
     const Definition* priorDef = nullptr;
+    bool incomplete = false;
     for (auto& child : fChildren) {
         if (MarkType::kAnchor == child->fMarkType) {
             continue;
@@ -552,6 +553,11 @@
         if (MarkType::kFormula == child->fMarkType) {
             continue;
         }
+        if (MarkType::kLine == child->fMarkType) {
+            SkASSERT(child->fChildren.size() > 0);
+            TextParser childDesc(child->fChildren[0]);
+            incomplete |= childDesc.startsWith("incomplete");
+        }
         if (MarkType::kList == child->fMarkType) {
             priorDef = child;
             continue;
@@ -577,7 +583,7 @@
         priorDef = nullptr;
     }
     if (!descEnd) {
-        return methodParser.reportError<bool>("missing description");
+        return incomplete ? true : methodParser.reportError<bool>("missing description");
     }
     TextParser description(fFileName, descStart, descEnd, fLineCount);
     // expect first word capitalized and pluralized. expect a trailing period
@@ -586,7 +592,9 @@
         description.reportWarning("expected capital");
     } else if ('.' != descEnd[-1]) {
         if (!defEnd || defEnd->fTerminator != descEnd) {
-            description.reportWarning("expected period");
+            if (!incomplete) {
+                description.reportWarning("expected period");
+            }
         }
     } else {
         if (!description.startsWith("For use by Android")) {
@@ -595,7 +603,9 @@
                 --description.fChar;
             }
             if ('s' != description.fChar[-1]) {
-                description.reportWarning("expected plural");
+                if (!incomplete) {
+                    description.reportWarning("expected plural");
+                }
             }
         }
     }
diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp
index d6594ea..eca7296 100644
--- a/tools/bookmaker/includeParser.cpp
+++ b/tools/bookmaker/includeParser.cpp
@@ -16,6 +16,7 @@
     { "",           KeyWord::kNone,         KeyProperty::kNone           },
     { "SK_API",     KeyWord::kSK_API,       KeyProperty::kModifier       },
     { "SK_BEGIN_REQUIRE_DENSE", KeyWord::kSK_BEGIN_REQUIRE_DENSE, KeyProperty::kModifier },
+    { "alignas",    KeyWord::kAlignAs,      KeyProperty::kModifier       },
     { "bool",       KeyWord::kBool,         KeyProperty::kNumber         },
     { "char",       KeyWord::kChar,         KeyProperty::kNumber         },
     { "class",      KeyWord::kClass,        KeyProperty::kObject         },
@@ -578,6 +579,9 @@
                 this->dumpMember(token);
                 continue;
             break;
+            case MarkType::kTypedef:
+                this->dumpTypedef(token, classDef.fName);
+            break;
             default:
                 SkASSERT(0);
         }
@@ -878,9 +882,10 @@
     this->lf(2);
 }
 
-bool IncludeParser::dumpGlobals() {
-    if (fIDefineMap.empty() && fIFunctionMap.empty() && fIEnumMap.empty() && fITemplateMap.empty()
-            && fITypedefMap.empty() && fIUnionMap.empty()) {
+bool IncludeParser::dumpGlobals(string* globalFileName, long int* globalTell) {
+    bool hasGlobals = !fIDefineMap.empty() || !fIFunctionMap.empty() || !fIEnumMap.empty()
+            || !fITemplateMap.empty()|| !fITypedefMap.empty() || !fIUnionMap.empty();
+    if (!hasGlobals) {
         return true;
     }
     size_t lastBSlash = fFileName.rfind('\\');
@@ -896,6 +901,7 @@
     lastSlash += 1;
     string globalsName = fFileName.substr(lastSlash, lastDotH - lastSlash);
     string fileName = globalsName + "_Reference.bmh";
+    *globalFileName = fileName;
     fOut = fopen(fileName.c_str(), "wb");
     if (!fOut) {
         SkDebugf("could not open output file %s\n", globalsName.c_str());
@@ -1007,9 +1013,10 @@
         }
         this->dumpCommonTail(*def);
     }
+    *globalTell = ftell(fOut);
     this->writeEndTag("Topic", topicName);
     this->lfAlways(1);
-    fclose(fOut);
+//    fclose(fOut);     // defer closing in case class needs to be also written here
     SkDebugf("wrote %s\n", fileName.c_str());
     return true;
 }
@@ -1038,6 +1045,45 @@
             || 0 == token.fName.find("private_");
 }
 
+bool IncludeParser::isMember(const Definition& token) const {
+    if ('f' == token.fStart[0] && isupper(token.fStart[1])) {
+        return true;
+    }
+    if (!islower(token.fStart[0])) {
+        return false;
+    }
+    // make an exception for SkTextBlob::RunBuffer, sole struct with members not in fXxxx format
+    if (string::npos != token.fFileName.find("SkTextBlob.h")) {
+        const Definition* structToken = token.fParent;
+        if (!structToken) {
+            return false;
+        }
+        if (KeyWord::kStruct != structToken->fKeyWord) {
+            structToken = token.fParent->fParent;
+            if (!structToken) {
+                return false;
+            }
+            if (KeyWord::kStruct != structToken->fKeyWord) {
+                return false;
+            }
+        }
+        SkASSERT(structToken->fTokens.size() > 0);
+        const Definition& child = structToken->fTokens.front();
+        string structName(child.fContentStart, child.length());
+        if ("RunBuffer" != structName) {
+            return false;
+        }
+        string tokenName(token.fContentStart, token.length());
+        string allowed[] = { "glyphs", "pos", "utf8text", "clusters" };
+        for (auto allow : allowed) {
+            if (allow == tokenName) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 bool IncludeParser::isOperator(const Definition& token) {
     return "operator" == token.fName.substr(0, 8);
 }
@@ -1083,34 +1129,48 @@
 }
 
 bool IncludeParser::dumpTokens() {
-    if (!this->dumpGlobals()) {
+    string globalFileName;
+    long int globalTell = 0;
+    if (!this->dumpGlobals(&globalFileName, &globalTell)) {
         return false;
     }
     for (const auto& member : fIClassMap) {
         if (string::npos != member.first.find("::")) {
             continue;
         }
-        if (!this->dumpTokens(member.first)) {
+        if (!this->dumpTokens(member.first, globalFileName, &globalTell)) {
             return false;
         }
     }
+    if (globalTell) {
+        fclose(fOut);
+    }
     return true;
 }
 
     // dump equivalent markup
-bool IncludeParser::dumpTokens(string skClassName) {
+bool IncludeParser::dumpTokens(string skClassName, string globalFileName, long int* globalTell) {
     string fileName = skClassName + "_Reference.bmh";
-    fOut = fopen(fileName.c_str(), "wb");
-    if (!fOut) {
-        SkDebugf("could not open output file %s\n", fileName.c_str());
-        return false;
+    if (globalFileName != fileName) {
+        fOut = fopen(fileName.c_str(), "wb");
+        if (!fOut) {
+            SkDebugf("could not open output file %s\n", fileName.c_str());
+            return false;
+        }
+    } else {
+        fseek(fOut, *globalTell, SEEK_SET);
+        this->lf(2);
+        this->writeBlockSeparator();
+        *globalTell = 0;
     }
     string prefixName = skClassName.substr(0, 2);
     string topicName = skClassName.length() > 2 && isupper(skClassName[2]) &&
         ("Sk" == prefixName || "Gr" == prefixName) ? skClassName.substr(2) : skClassName;
-    this->writeTagNoLF("Topic", topicName);
-    this->writeEndTag("Alias", topicName + "_Reference");
-    this->lf(2);
+    if (globalFileName != fileName) {
+        this->writeTagNoLF("Topic", topicName);
+        this->writeEndTag("Alias", topicName + "_Reference");
+        this->lf(2);
+    }
     auto& classMap = fIClassMap[skClassName];
     SkASSERT(KeyWord::kClass == classMap.fKeyWord || KeyWord::kStruct == classMap.fKeyWord);
     const char* containerType = KeyWord::kClass == classMap.fKeyWord ? "Class" : "Struct";
@@ -1258,6 +1318,15 @@
     return true;
 }
 
+void IncludeParser::dumpTypedef(const Definition& token, string className) {
+    this->writeTag("Typedef");
+    this->writeSpace();
+    this->writeString(token.fName);
+    this->writeTagTable("Line", "incomplete");
+    this->lf(2);
+    this->dumpComment(token);
+}
+
 bool IncludeParser::findComments(const Definition& includeDef, Definition* markupDef) {
     // add comment preceding class, if any
     const Definition* parent = includeDef.fParent;
@@ -1341,6 +1410,32 @@
     return parent ? parent->fBracket : Bracket::kNone;
 }
 
+bool IncludeParser::inAlignAs() const {
+    if (fParent->fTokens.size() < 2) {
+        return false;
+    }
+    auto reverseIter = fParent->fTokens.end();
+    bool checkForBracket = true;
+    while (fParent->fTokens.begin() != reverseIter) {
+        std::advance(reverseIter, -1);
+        if (checkForBracket) {
+            if (Definition::Type::kBracket != reverseIter->fType) {
+                return false;
+            }
+            if (Bracket::kParen != reverseIter->fBracket) {
+                return false;
+            }
+            checkForBracket = false;
+            continue;
+        }
+        if (Definition::Type::kKeyWord != reverseIter->fType) {
+            return false;
+        }
+        return KeyWord::kAlignAs == reverseIter->fKeyWord;
+    }
+    return false;
+}
+
 // caller just returns, so report error here
 bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) {
     SkASSERT(includeDef->fTokens.size() > 0);
@@ -1350,6 +1445,14 @@
         // todo : documentation is ignoring this for now
         iter = std::next(iter);
     }
+    bool hasAlignAs = iter->fKeyWord == KeyWord::kAlignAs;
+    if (hasAlignAs) {
+        iter = std::next(iter);
+        if (Definition::Type::kBracket != iter->fType || Bracket::kParen != iter->fBracket) {
+            return includeDef->reportError<bool>("expected alignas argument");
+        }
+        iter = std::next(iter);
+    }
     string nameStr(iter->fStart, iter->fContentEnd - iter->fStart);
     includeDef->fName = nameStr;
     iter = std::next(iter);
@@ -1378,7 +1481,18 @@
 //    if (1 != includeDef->fChildren.size()) {
 //        return false;  // fix me: SkCanvasClipVisitor isn't correctly parsed
 //    }
-    includeDef = includeDef->fChildren.front();
+    auto includeDefIter = includeDef->fChildren.begin();
+    if (hasAlignAs) {
+        SkASSERT(includeDef->fChildren.end() != includeDefIter);
+        SkASSERT(Bracket::kParen == (*includeDefIter)->fBracket);
+        std::advance(includeDefIter, 1);
+    }
+    if (includeDef->fChildren.end() != includeDefIter
+            && Bracket::kAngle == (*includeDefIter)->fBracket) {
+        std::advance(includeDefIter, 1);
+    }
+    includeDef = *includeDefIter;
+    SkASSERT(Bracket::kBrace == includeDef->fBracket);
     iter = includeDef->fTokens.begin();
     // skip until public
     int publicIndex = 0;
@@ -1402,7 +1516,7 @@
     const char* privateName = kKeyWords[(int) KeyWord::kPrivate].fName;
     size_t privateLen = strlen(privateName);
     auto childIter = includeDef->fChildren.begin();
-    while ((*childIter)->fPrivate) {
+    while (includeDef->fChildren.end() != childIter && (*childIter)->fPrivate) {
         std::advance(childIter, 1);
     }
     while (childIter != includeDef->fChildren.end()) {
@@ -1861,9 +1975,6 @@
         tokenIter = operatorCheck;
     }
     string nameStr(tokenIter->fStart, nameEnd - tokenIter->fStart);
-    if (string::npos != nameStr.find("sizeof")) {
-        SkDebugf("");
-    }
     if (addConst) {
         nameStr += "_const";
     }
@@ -2070,7 +2181,7 @@
                             fAttrDeprecated = &*tokenIter;
                             break;
                         }
-                        if ('f' == previousToken.fStart[0] && isupper(previousToken.fStart[1])) {
+                        if (this->isMember(*tokenIter)) {
                             break;
                         }
                         if (Bracket::kPound == child->fParent->fBracket &&
@@ -2391,7 +2502,7 @@
             if (match == this->topBracket()) {
                 this->popBracket();
                 if (!fInFunction) {
-                    fInFunction = ')' == test;
+                    fInFunction = ')' == test && !this->inAlignAs();
                 } else {
                     fInFunction = '}' != test;
                 }
@@ -2587,7 +2698,7 @@
                         fParent->fTokens.begin() != tokenIter; ) {
                     --tokenIter;
                     if (tokenIter->fLineCount == fLineCount) {
-                        if ('f' == tokenIter->fStart[0] && isupper(tokenIter->fStart[1])) {
+                        if (this->isMember(*tokenIter)) {
                             if (namedIter != fParent->fTokens.end()) {
                                 return reportError<bool>("found two named member tokens");
                             }
diff --git a/tools/bookmaker/includeWriter.cpp b/tools/bookmaker/includeWriter.cpp
index 922f220..d0981ec 100644
--- a/tools/bookmaker/includeWriter.cpp
+++ b/tools/bookmaker/includeWriter.cpp
@@ -1218,6 +1218,7 @@
                 case KeyWord::kSize_t:
                 case KeyWord::kFloat:
                 case KeyWord::kBool:
+                case KeyWord::kChar:
                 case KeyWord::kVoid:
                     if (!typeStart) {
                         typeStart = &token;
@@ -1781,6 +1782,7 @@
                         memberStart = &child;
                     }
                     break;
+                case KeyWord::kAlignAs:
                 case KeyWord::kPublic:
                 case KeyWord::kPrivate:
                 case KeyWord::kProtected:
@@ -2691,6 +2693,7 @@
 
     // find end of copyright header
     fChar = fStart;
+    this->skipWhiteSpace();
     if (!this->skipExact(
             "/*\n"
             " * Copyright ")) {
diff --git a/tools/bookmaker/mdOut.cpp b/tools/bookmaker/mdOut.cpp
index 4fdc206..c3a985c 100644
--- a/tools/bookmaker/mdOut.cpp
+++ b/tools/bookmaker/mdOut.cpp
@@ -2121,7 +2121,7 @@
 
 void MdOut::subtopicOut(string name) {
     const Definition* topicParent = fSubtopic ? fSubtopic->topicParent() : nullptr;
-    Definition* csParent = this->csParent();
+    Definition* csParent = fRoot && fRoot->isStructOrClass() ? fRoot : this->csParent();
     if (!csParent) {
         auto csIter = std::find_if(topicParent->fChildren.begin(), topicParent->fChildren.end(),
                 [](const Definition* def){ return MarkType::kEnum == def->fMarkType
diff --git a/tools/bookmaker/spellCheck.cpp b/tools/bookmaker/spellCheck.cpp
index 39621db..5b1ab1d 100644
--- a/tools/bookmaker/spellCheck.cpp
+++ b/tools/bookmaker/spellCheck.cpp
@@ -22,6 +22,8 @@
 words in external not seen
 
 look for x-bit but allow x bits
+
+don't treat 'pos' or 'glyphs' as spell-checkable as in 'RunBuffer.pos' or 'RunBuffer.glyphs'
  */
 
 struct CheckEntry {
@@ -469,6 +471,11 @@
                 allLower = false;
             case '-':  // note that dash doesn't clear allLower
                 break;
+            case '!':
+                if (!inQuotes) {
+                    wordEnd = chPtr;
+                }
+                break;
             case '\n':
                 ++fLocalLine;
                 // fall through
@@ -663,9 +670,6 @@
         }
         iter->second.fCount += 1;
     } else {
-    if ("e" == str) {
-        SkDebugf("");
-    }
         CheckEntry* entry = &mappy[str];
         entry->fFile = fFileName;
         entry->fLine = fLineCount + fLocalLine;