sync docs up with tip of tree

Also check in work in progress for blend modes,
round rects, and a placeholder for pictures.

One minor include change to add a parameter name
for SkBlendMode function.

TBR=reed@google.com
R=caryclark@google.com

Docs-Preview: https://skia.org/?cl=134200
Bug: skia:6898
Change-Id: I5d2a9221d61edb32d9c7edbb3193401605b2b513
Reviewed-on: https://skia-review.googlesource.com/134200
Reviewed-by: Cary Clark <caryclark@google.com>
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/includeParser.cpp b/tools/bookmaker/includeParser.cpp
index d6aa447..fdaf0cc 100644
--- a/tools/bookmaker/includeParser.cpp
+++ b/tools/bookmaker/includeParser.cpp
@@ -136,6 +136,12 @@
         return true;
     }
     KeyWord keyWord = FindKey(fIncludeWord, fChar);
+    if (KeyWord::kClass == keyWord || KeyWord::kStruct == keyWord) {
+        Bracket bracket = this->topBracket();
+        if (Bracket::kParen == bracket) {
+            return true;
+        }
+    }
     if (KeyWord::kNone != keyWord) {
         if (KeyProperty::kPreprocessor != kKeyWords[(int) keyWord].fProperty) {
             this->addKeyword(keyWord);
@@ -360,9 +366,6 @@
                     }
                     if (def->crossCheck2(token)) {
                         def->fVisited = true;
-                        if (MarkType::kDefinedBy == def->fMarkType) {
-                            def->fParent->fVisited = true;
-                        }
                         if (token.fDeprecated && !def->fDeprecated) {
                             fFailed = !def->reportError<bool>("expect bmh to be marked deprecated");
                         }
@@ -556,6 +559,9 @@
             this->writeBlockSeparator();
         }
         switch (token.fMarkType) {
+            case MarkType::kConst:
+                this->dumpConst(token, classDef.fName);
+            break;
             case MarkType::kEnum:
             case MarkType::kEnumClass:
                 this->dumpEnum(token, token.fName);
@@ -753,6 +759,15 @@
     this->lf(2);
 }
 
+void IncludeParser::dumpConst(const Definition& token, string className) {
+    this->writeTag("Const");
+    this->writeSpace();
+    this->writeString(token.fName);
+    this->writeTagTable("Line", "incomplete");
+    this->lf(2);
+    this->dumpComment(token);
+}
+
 void IncludeParser::dumpDefine(const Definition& token) {
     this->writeTag("Define", token.fName);
     this->lf(2);
@@ -859,6 +874,10 @@
 }
 
 bool IncludeParser::dumpGlobals() {
+    if (fIDefineMap.empty() && fIFunctionMap.empty() && fIEnumMap.empty() && fITemplateMap.empty()
+            && fITypedefMap.empty() && fIUnionMap.empty()) {
+        return true;
+    }
     size_t lastBSlash = fFileName.rfind('\\');
     size_t lastSlash = fFileName.rfind('/');
     size_t lastDotH = fFileName.rfind(".h");
@@ -881,16 +900,10 @@
     string topicName = globalsName.length() > 2 && isupper(globalsName[2]) &&
         ("Sk" == prefixName || "Gr" == prefixName) ? globalsName.substr(2) : globalsName;
     this->writeTagNoLF("Topic", topicName);
-    this->writeTag("Alias", topicName + "_Reference");
+    this->writeEndTag("Alias", topicName + "_Reference");
     this->lf(2);
     this->writeTag("Subtopic", "Overview");
-    fIndent += 4;
-    this->writeTag("Subtopic", "Subtopic");
-    fIndent += 4;
     this->writeTag("Populate");
-    fIndent -= 4;
-    this->writeEndTag();
-    fIndent -= 4;
     this->writeEndTag();
     this->lf(2);
     if (!fIDefineMap.empty()) {
@@ -1037,7 +1050,7 @@
             name = name.substr(0, constPos) + "_const";
         }
     }
-    this->writeString(name);
+    this->writeBlock((int) name.size(), name.c_str());
     string inType;
     if (this->isConstructor(token, className)) {
         inType = "Constructor";
@@ -1047,13 +1060,7 @@
         inType = "incomplete";
     }
     this->writeTag("In", inType);
-    this->writeTag("Line");
-    this->writeSpace(1);
-    this->writeString("#");
-    this->writeSpace(1);
-    this->writeString("incomplete");
-    this->writeSpace(1);
-    this->writeString("##");
+    this->writeTagTable("Line", "incomplete");
     this->lf(2);
     this->dumpComment(token);
 }
@@ -1097,7 +1104,7 @@
     string topicName = skClassName.length() > 2 && isupper(skClassName[2]) &&
         ("Sk" == prefixName || "Gr" == prefixName) ? skClassName.substr(2) : skClassName;
     this->writeTagNoLF("Topic", topicName);
-    this->writeTag("Alias", topicName + "_Reference");
+    this->writeEndTag("Alias", topicName + "_Reference");
     this->lf(2);
     auto& classMap = fIClassMap[skClassName];
     SkASSERT(KeyWord::kClass == classMap.fKeyWord || KeyWord::kStruct == classMap.fKeyWord);
@@ -1118,6 +1125,7 @@
     bool hasConstructor = false;
     bool hasMember = false;
     bool hasOperator = false;
+    bool hasStruct = false;
     for (const auto& oneClass : fIClassMap) {
         if (skClassName + "::" != oneClass.first.substr(0, skClassName.length() + 2)) {
             continue;
@@ -1125,6 +1133,13 @@
         hasClass = true;
         break;
     }
+    for (const auto& oneStruct : fIStructMap) {
+        if (skClassName + "::" != oneStruct.first.substr(0, skClassName.length() + 2)) {
+            continue;
+        }
+        hasStruct = true;
+        break;
+    }
     for (const auto& token : classMap.fTokens) {
         if (Definition::Type::kMark != token.fType || MarkType::kMethod != token.fMarkType) {
             continue;
@@ -1146,18 +1161,12 @@
         hasMember = true;
     }
     this->writeTag("Subtopic", "Overview");
-    fIndent += 4;
-    this->writeTag("Subtopic", "Subtopic");
-    fIndent += 4;
     this->writeTag("Populate");
-    fIndent -= 4;
-    this->writeEndTag();
-    fIndent -= 4;
     this->writeEndTag();
     this->lf(2);
 
     if (hasClass) {
-        this->writeTag("Subtopic", "Class_or_Struct");
+        this->writeTag("Subtopic", "Class");
         this->writeTag("Populate");
         this->writeEndTag();
         this->lf(2);
@@ -1186,6 +1195,12 @@
         this->writeEndTag();
         this->lf(2);
     }
+    if (hasStruct) {
+        this->writeTag("Subtopic", "Struct");
+        this->writeTag("Populate");
+        this->writeEndTag();
+        this->lf(2);
+    }
     for (auto& oneEnum : fIEnumMap) {
         this->writeBlockSeparator();
         this->dumpEnum(*oneEnum.second, oneEnum.first);
@@ -1210,6 +1225,7 @@
         SkASSERT(KeyWord::kClass == keyword || KeyWord::kStruct == keyword);
         const char* containerType = KeyWord::kClass == keyword ? "Class" : "Struct";
         this->writeTag(containerType, innerName);
+        this->writeTagTable("Line", "incomplete");
         this->lf(2);
         this->writeTag("Code");
         this->writeEndTag("ToDo", "fill this in manually");
@@ -1307,6 +1323,19 @@
     return &markupDef;
 }
 
+Definition* IncludeParser::parentBracket(Definition* parent) const {
+    while (parent && Definition::Type::kBracket != parent->fType) {
+        parent = parent->fParent;
+    }
+    return parent;
+}
+
+Bracket IncludeParser::grandParentBracket() const {
+    Definition* parent = parentBracket(fParent);
+    parent = parentBracket(parent ? parent->fParent : nullptr);
+    return parent ? parent->fBracket : Bracket::kNone;
+}
+
 // caller just returns, so report error here
 bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) {
     SkASSERT(includeDef->fTokens.size() > 0);
@@ -1663,7 +1692,7 @@
         parser.skipToNonName();
         string memberName(memberStart, parser.fChar);
         if (parser.eof() || !parser.skipWhiteSpace()) {
-            return this->reportError<bool>("enum member must end with comma 1");
+            return parser.reportError<bool>("enum member must end with comma 1");
         }
         const char* dataStart = parser.fChar;
         if ('=' == parser.peek()) {
@@ -1674,7 +1703,7 @@
             continue;
         }
         if (parser.eof() || ',' != parser.peek()) {
-            return this->reportError<bool>("enum member must end with comma 2");
+            return parser.reportError<bool>("enum member must end with comma 2");
         }
         dataEnd = parser.fChar;
         const char* start = parser.anyOf("/\n");
@@ -1867,7 +1896,7 @@
         }
         break;
     }
-    tokenIter->fName = nameStr;
+    tokenIter->fName = nameStr;     // simple token stream, OK if name is duplicate
     tokenIter->fMarkType = MarkType::kMethod;
     tokenIter->fPrivate = string::npos != nameStr.find("::");
     auto testIter = child->fParent->fTokens.begin();
@@ -1934,15 +1963,19 @@
     markupDef->fTokens.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount,
             markupDef, '\0');
     Definition* markupChild = &markupDef->fTokens.back();
-    // do find instead -- I wonder if there is a way to prevent this in c++
-    IClassDefinition& classDef = fIClassMap[markupDef->fName];
-    SkASSERT(classDef.fStart);
-    string uniqueName = this->uniqueName(classDef.fMethods, nameStr);
-    markupChild->fName = uniqueName;
-    if (!this->findComments(*child, markupChild)) {
-        return false;
+    // TODO: I wonder if there is a way to prevent looking up by operator[] (creating empty) ?
+    {
+        auto mapIter = fIClassMap.find(markupDef->fName);
+        SkASSERT(fIClassMap.end() != mapIter);
+        IClassDefinition& classDef = mapIter->second;
+        SkASSERT(classDef.fStart);
+        string uniqueName = this->uniqueName(classDef.fMethods, nameStr);
+        markupChild->fName = uniqueName;
+        if (!this->findComments(*child, markupChild)) {
+            return false;
+        }
+        classDef.fMethods[uniqueName] = markupChild;
     }
-    classDef.fMethods[uniqueName] = markupChild;
     return true;
 }
 
@@ -2324,6 +2357,8 @@
                 break;
             }
             this->pushBracket(Bracket::kAngle);
+            // this angle bracket may be an operator or may be a bracket
+            // wait for balancing close angle, if any, to decide
             break;
         case ')':
         case ']':
@@ -2340,8 +2375,9 @@
                 }
             }
             bool popBraceParent = fInBrace == fParent;
-            if ((')' == test ? Bracket::kParen :
-                    ']' == test ? Bracket::kSquare : Bracket::kBrace) == this->topBracket()) {
+            Bracket match = ')' == test ? Bracket::kParen :
+                    ']' == test ? Bracket::kSquare : Bracket::kBrace;
+            if (match == this->topBracket()) {
                 this->popBracket();
                 if (!fInFunction) {
                     fInFunction = ')' == test;
@@ -2350,6 +2386,10 @@
                 }
             } else if (')' == test && Bracket::kDebugCode == this->topBracket()) {
                 this->popBracket();
+            } else if (Bracket::kAngle == this->topBracket()
+                    && match == this->grandParentBracket()) {
+                this->popBracket();
+                this->popBracket();
             } else {
                 return reportError<bool>("malformed close bracket");
             }
@@ -2374,6 +2414,7 @@
                 break;
             }
             if (Bracket::kAngle == this->topBracket()) {
+                // looks like angle pair are braces, not operators
                 this->popBracket();
             } else {
                 return reportError<bool>("malformed close angle bracket");
@@ -2707,7 +2748,12 @@
     if (fIStructMap.end() != fIStructMap.find(root)) {
         return true;
     }
-    // TODO incomplete: probably need to look in other places for class-less includes like SkColor.h
+    if (fIEnumMap.end() != fIEnumMap.find(root)) {
+        return true;
+    }
+    if (fIFunctionMap.end() != fIFunctionMap.find(root)) {
+        return true;
+    }
     return false;
 }
 
@@ -2743,3 +2789,8 @@
     SkString fullName = SkOSPath::Join(docs, baseName.c_str());
     remove(fullName.c_str());
 }
+
+Bracket IncludeParser::topBracket() const {
+    Definition* parent = this->parentBracket(fParent);
+    return parent ? parent->fBracket : Bracket::kNone;
+}