work on generation of rect, bitmap, matrix markup

TBR=caryclark@google.com
Bug: skia:6898
Change-Id: I501d87341afa2f8d548b4d02415375032a46e96e
Reviewed-on: https://skia-review.googlesource.com/47420
Reviewed-by: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp
index 1000a03..ee2b95a 100644
--- a/tools/bookmaker/includeParser.cpp
+++ b/tools/bookmaker/includeParser.cpp
@@ -105,9 +105,7 @@
             }
         }
         if (!found) {
-            this->keywordStart("Param");
-            fprintf(fOut, "%s  ", methodParam.c_str());
-            this->keywordEnd();
+            this->writeEndTag("Param", methodParam, 2);
         }
     }
     for (auto& foundParam : foundParams) {
@@ -450,90 +448,38 @@
             continue;
         }
         if (MarkType::kMember != token.fMarkType) {
-            fprintf(fOut, "%s",
-              "# ------------------------------------------------------------------------------\n");
-            fprintf(fOut, ""                                                                  "\n");
+            this->writeString(
+              "# ------------------------------------------------------------------------------");
+            this->lf(2);
         }
         switch (token.fMarkType) {
             case MarkType::kEnum:
-                fprintf(fOut, "#Enum %s"                                                     "\n",
-                        token.fName.c_str());
-                fprintf(fOut, ""                                                             "\n");
-                fprintf(fOut, "#Code"                                                        "\n");
-                fprintf(fOut, "    enum %s {"                                                "\n",
-                        token.fName.c_str());
-                for (auto& child : token.fChildren) {
-                    fprintf(fOut, "        %s %.*s"                                          "\n",
-                            child->fName.c_str(), child->length(), child->fContentStart);
-                }
-                fprintf(fOut, "    };"                                                       "\n");
-                fprintf(fOut, "##"                                                           "\n");
-                fprintf(fOut, ""                                                             "\n");
-                this->dumpComment(&token);
-                for (auto& child : token.fChildren) {
-                    fprintf(fOut, "#Const %s", child->fName.c_str());
-                    TextParser val(child);
-                    if (!val.eof()) {
-                        if ('=' == val.fStart[0] || ',' == val.fStart[0]) {
-                            val.next();
-                            val.skipSpace();
-                            const char* valEnd = val.anyOf(",\n");
-                            if (!valEnd) {
-                                valEnd = val.fEnd;
-                            }
-                            fprintf(fOut, " %.*s", (int) (valEnd - val.fStart), val.fStart);
-                        } else {
-                            fprintf(fOut, " %.*s", 
-                                    (int) (child->fContentEnd - child->fContentStart),
-                                    child->fContentStart);
-                        }
-                    }
-                    fprintf(fOut, ""                                                         "\n");
-                    for (auto& token : child->fTokens) {
-                        if (MarkType::kComment == token.fMarkType) {
-                            this->dumpComment(&token);
-                        }
-                    }
-                    fprintf(fOut, "##"                                                       "\n");
-                }
-                fprintf(fOut, ""                                                             "\n");
+                this->dumpEnum(token);
             break;
             case MarkType::kMethod:
-                fprintf(fOut, "#Method %.*s"                                                 "\n",
-                        token.length(), token.fStart);
-                lfAlways(1);
-                this->dumpComment(&token);
+                this->dumpMethod(token);
             break;
             case MarkType::kMember:
-                this->keywordStart("Member");
-                fprintf(fOut, "%.*s  %s  ", (int) (token.fContentEnd - token.fContentStart),
-                        token.fContentStart, token.fName.c_str());           
-                lfAlways(1);
-                for (auto child : token.fChildren) {
-                    fprintf(fOut, "%.*s", (int) (child->fContentEnd - child->fContentStart),
-                            child->fContentStart);
-                    lfAlways(1);
-                }
-                this->keywordEnd();
+                this->dumpMember(token);
                 continue;
             break;
             default:
                 SkASSERT(0);
         }
         this->lf(2);
-        fprintf(fOut, "#Example"                                                             "\n");
-        fprintf(fOut, "##"                                                                   "\n");
-        fprintf(fOut, ""                                                                     "\n");
-        fprintf(fOut, "#ToDo incomplete ##"                                                  "\n");
-        fprintf(fOut, ""                                                                     "\n");
-        fprintf(fOut, "##"                                                                   "\n");
-        fprintf(fOut, ""                                                                     "\n");
+        this->writeTag("Example");
+        this->writeEndTag();
+        this->lf(2);
+        this->writeEndTag("ToDo", "incomplete");
+        this->lf(2);
+        this->writeEndTag();
+        this->lf(2);
     }
 }
-void IncludeParser::dumpComment(Definition* token) {
-    fLineCount = token->fLineCount;
-    fChar = fLine = token->fContentStart;
-    fEnd = token->fContentEnd;
+void IncludeParser::dumpComment(const Definition& token) {
+    fLineCount = token.fLineCount;
+    fChar = fLine = token.fContentStart;
+    fEnd = token.fContentEnd;
     bool sawParam = false;
     bool multiline = false;
     bool sawReturn = false;
@@ -542,11 +488,11 @@
     vector<string> methodParams;
     vector<string> foundParams;
     Definition methodName;
-    TextParser methodParser(token->fFileName, token->fContentStart, token->fContentEnd,
-            token->fLineCount);
-    if (MarkType::kMethod == token->fMarkType) {
-        methodName.fName = string(token->fContentStart,
-                (int) (token->fContentEnd - token->fContentStart));
+    TextParser methodParser(token.fFileName, token.fContentStart, token.fContentEnd,
+            token.fLineCount);
+    if (MarkType::kMethod == token.fMarkType) {
+        methodName.fName = string(token.fContentStart,
+                (int) (token.fContentEnd - token.fContentStart));
         methodHasReturn = !methodParser.startsWith("void ")
                 && !methodParser.strnchr('~', methodParser.fEnd);
         const char* paren = methodParser.strnchr('(', methodParser.fEnd);
@@ -561,8 +507,14 @@
             methodParams.push_back(paramName);
         } while (')' != nextEnd[0]);
     }
-    for (const auto& child : token->fTokens) {
+    for (const auto& child : token.fTokens) {
+        if (Definition::Type::kMark == child.fType && MarkType::kMember == child.fMarkType) {
+            break;
+        }
         if (Definition::Type::kMark == child.fType && MarkType::kComment == child.fMarkType) {
+            if (child.fPrivate) {
+                break;
+            }
             if ('@' == child.fContentStart[0]) {
                 TextParser parser(&child);
                 do {
@@ -585,9 +537,9 @@
                             }
                             if (sawParam) {
                                 if (multiline) {
-                                    this->lfAlways(1);
+                                    this->lf(1);
                                 }
-                                this->keywordEnd();
+                                this->writeEndTag();
                             } else {
                                 if (sawComment) {
                                     this->nl();
@@ -595,10 +547,10 @@
                                 this->lf(2);
                             }
                             foundParams.emplace_back(piece);
-                            this->keywordStart("Param");
-                            fprintf(fOut, "%s  ", piece.c_str());
-                            fprintf(fOut, "%.*s", (int) (parser.fEnd - parser.fChar), parser.fChar);
-                            this->lfAlways(1);
+                            this->writeTag("Param", piece);
+                            this->writeSpace(2);
+                            this->writeBlock(parser.fEnd - parser.fChar, parser.fChar);
+                            this->lf(1);
                             sawParam = true;
                             sawComment = false;
                         } while (parmName.length());
@@ -610,43 +562,59 @@
                         }
                         if (sawParam) {
                             if (multiline) {
-                                this->lfAlways(1);
+                                this->lf(1);
                             }
-                            this->keywordEnd();
+                            this->writeEndTag();
                         }
                         this->checkForMissingParams(methodParams, foundParams);
                         sawParam = false;
                         sawComment = false;
                         multiline = false;
                         this->lf(2);
-                        this->keywordStart("Return");
-                        fprintf(fOut, "%.*s ", (int) (parser.fEnd - parser.fChar),
-                                parser.fChar);
-                        this->lfAlways(1);
+                        this->writeTag("Return");
+                        this->writeSpace(2);
+                        this->writeBlock(parser.fEnd - parser.fChar, parser.fChar);
+                        this->lf(1);
                         sawReturn = true;
                         parser.skipTo(parser.fEnd);
                     } else {
                         this->reportError("unexpected doxygen directive");
                     }
                 } while (!parser.eof());
-            } else {
-                if (sawComment) {
-                    this->nl();
+            } else if (child.length() > 1) {
+                const char* start = child.fContentStart;
+                ptrdiff_t length = child.fContentEnd - start;
+                SkASSERT(length >= 0);
+                while (length && '/' == start[0]) {
+                    start += 1;
+                    --length;
                 }
-                this->lf(1);
-                fprintf(fOut, "%.*s ", child.length(), child.fContentStart);
-                sawComment = true;
-                if (sawParam || sawReturn) {
-                    multiline = true;
+                while (length && '/' == start[length - 1]) {
+                    length -= 1;
+                    if (length && '*' == start[length - 1]) {
+                        length -= 1;
+                    }
+                }
+                if (length) {
+                    this->lfAlways(sawComment || sawParam || sawReturn ? 1 : 2);
+                    if (sawParam || sawReturn) {
+                        this->indentToColumn(8);
+                    }
+                    this->writeBlock(length, start);
+                    this->writeSpace();
+                    sawComment = true;
+                    if (sawParam || sawReturn) {
+                        multiline = true;
+                    }
                 }
             }
         }
     }
     if (sawParam || sawReturn) {
         if (multiline) {
-            this->lfAlways(1);
+            this->lf(1);
         }
-        this->keywordEnd();
+        this->writeEndTag();
     }
     if (!sawReturn) {
         if (!sawParam) {
@@ -665,15 +633,145 @@
                 this->nl();
             }
             this->lf(2);
-            this->keywordStart("Return");
-            this->keywordEnd();
+            this->writeEndTag("Return");
         }
     }
 }
 
-    // dump equivalent markup 
+void IncludeParser::dumpEnum(const Definition& token) {
+    this->writeTag("Enum", token.fName);
+    this->lf(2);
+    this->writeString("#Code");
+    this->lfAlways(1);
+    this->indentToColumn(4);
+    this->writeString("enum");
+    this->writeSpace();
+    if ("_anonymous" != token.fName.substr(0, 10)) {
+        this->writeString(token.fName);
+        this->writeSpace();
+    }
+    this->writeString("{");
+    this->lfAlways(1);
+    for (auto& child : token.fChildren) {
+        this->indentToColumn(8);
+        this->writeString(child->fName);
+        if (child->length()) {
+            this->writeSpace();
+            this->writeBlock(child->length(), child->fContentStart);
+        }
+        if (',' != fLastChar) {
+            this->writeString(",");
+        }
+        this->lfAlways(1);
+    }
+    this->indentToColumn(4);
+    this->writeString("};");
+    this->lf(1);
+    this->writeString("##");
+    this->lf(2);
+    this->dumpComment(token);
+    for (auto& child : token.fChildren) {
+    //     start here;
+        // get comments before
+        // or after const values
+        this->writeString("#Const");
+        this->writeSpace();
+        this->writeString(child->fName);
+        TextParser val(child);
+        if (!val.eof()) {
+            if ('=' == val.fStart[0] || ',' == val.fStart[0]) {
+                val.next();
+                val.skipSpace();
+                const char* valEnd = val.anyOf(",\n");
+                if (!valEnd) {
+                    valEnd = val.fEnd;
+                }
+                this->writeSpace();
+                this->writeBlock(valEnd - val.fStart, val.fStart);
+            } else {
+                this->writeSpace();
+                this->writeDefinition(*child);
+            }
+        }
+        this->lf(1);
+        for (auto comment : child->fChildren) {
+            if (MarkType::kComment == comment->fMarkType) {
+                TextParser parser(comment);
+                parser.skipExact("*");
+                parser.skipExact("*");
+                while (!parser.eof() && parser.skipWhiteSpace()) {
+                    parser.skipExact("*");
+                    parser.skipWhiteSpace();
+                    const char* start = parser.fChar;
+                    parser.skipToEndBracket('\n');
+                    this->lf(1);
+                    this->writeBlock(parser.fChar - start, start);
+                }
+            }
+        }
+        this->writeEndTag();
+    }
+    this->lf(2);
+}
+
+void IncludeParser::dumpMethod(const Definition& token) {
+    this->writeString("#Method");
+    this->writeSpace();
+    if ("SK_TO_STRING_NONVIRT" == token.fName) {
+        this->writeString("void toString(SkString* str) const;");
+        this->lf(2);
+        this->writeEndTag("DefinedBy", "SK_TO_STRING_NONVIRT()");
+        this->lf(2);
+        this->writeTag("Private");
+        this->lf(1);
+        this->writeString("macro expands to: void toString(SkString* str) const;");
+        this->writeEndTag();
+        this->lf(2);
+        const char desc[] = 
+                "Creates string representation. The representation is read by\n"
+                "internal debugging tools. The interface and implementation may be\n"
+                "suppressed by defining SK_IGNORE_TO_STRING.";
+        this->writeBlock(sizeof(desc) - 1, desc);
+        this->lf(2);
+        this->writeTag("Param", "str");
+        this->writeSpace(2);
+        this->writeString("storage for string representation");
+        this->writeSpace();
+        this->writeString("##");
+        this->lf(2);
+        return;
+    }
+    this->writeBlock(token.length(), token.fStart);
+    this->lf(1);
+    this->dumpComment(token);
+}
+
+void IncludeParser::dumpMember(const Definition& token) {
+    this->writeTag("Member");
+    this->writeSpace();
+    this->writeDefinition(token, token.fName, 2);
+    lf(1);
+    for (auto child : token.fChildren) {
+        this->writeDefinition(*child);
+    }
+    this->writeEndTag();
+    lf(2);
+}
+
 bool IncludeParser::dumpTokens(const string& dir) {
-    string skClassName = this->className();
+    for (const auto& member : fIClassMap) {
+        if (string::npos != member.first.find("::")) {
+            continue;
+        }
+        if (!this->dumpTokens(dir, member.first)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+    // dump equivalent markup 
+bool IncludeParser::dumpTokens(const string& dir, const string& skClassName) {
     string fileName = dir;
     if (dir.length() && '/' != dir[dir.length() - 1]) {
         fileName += '/';
@@ -687,19 +785,20 @@
     string prefixName = skClassName.substr(0, 2);
     string topicName = skClassName.length() > 2 && isupper(skClassName[2]) &&
         ("Sk" == prefixName || "Gr" == prefixName) ? skClassName.substr(2) : skClassName;
-    fprintf(fOut, "#Topic %s", topicName.c_str());
-    this->lfAlways(2);
-    fprintf(fOut, "#Class %s", skClassName.c_str());
-    this->lfAlways(2);
+    this->writeTagNoLF("Topic", topicName);
+    this->writeTag("Alias", topicName + "_Reference");
+    this->lf(2);
     auto& classMap = fIClassMap[skClassName];
+    const char* containerType = kKeyWords[(int) classMap.fKeyWord].fName;
+    this->writeTag(containerType, skClassName);
+    this->lf(2);
     auto& tokens = classMap.fTokens;
     for (auto& token : tokens) {
         if (Definition::Type::kMark != token.fType || MarkType::kComment != token.fMarkType) {
             continue;
         }
-        fprintf(fOut, "%.*s", (int) (token.fContentEnd - token.fContentStart),
-                token.fContentStart);
-        this->lfAlways(1);
+        this->writeDefinition(token);
+        this->lf(1);
     }
     this->lf(2);
     string className(skClassName.substr(2));
@@ -713,96 +812,129 @@
         maxLen = SkTMax(maxLen, structName.length());
         sortedClasses.emplace_back(structName);
     }
-    fprintf(fOut, "#Topic Overview");
-    this->lfAlways(2);
-    fprintf(fOut, "#Subtopic %s_Structs", className.c_str());
-    this->lfAlways(1);
-    fprintf(fOut, "#Table");
-    this->lfAlways(1);
-    fprintf(fOut, "#Legend");
-    this->lfAlways(1);
-    fprintf(fOut, "# %-*s # description ##", (int) maxLen, "struct");
-    this->lfAlways(1);
-    fprintf(fOut, "#Legend ##");
-    this->lfAlways(1);
-    fprintf(fOut, "#Table ##");
-    this->lfAlways(1);
-    for (auto& name : sortedClasses) {
-        fprintf(fOut, "# %-*s # ##", (int) maxLen, name.c_str());
-        this->lfAlways(1);
+    this->writeTag("Topic", "Overview");
+    this->lf(2);
+    this->writeTag("Subtopic", "Subtopics");
+    this->writeEndTag("ToDo", "manually add subtopics");
+    this->writeTableHeader("topics", 0, "description");
+    this->writeTableTrailer();
+    this->writeEndTag();
+    this->lf(2);
+    if (maxLen) {
+        this->writeTag("Subtopic", "Structs");
+        this->writeTableHeader("description", maxLen, "struct");
+         for (auto& name : sortedClasses) {
+             this->writeTableRow(maxLen, name);
+        }
+        this->writeTableTrailer();
+        this->writeEndTag("Subtopic");
+        this->lf(2);
     }
-    fprintf(fOut, "#Subtopic ##");
-    this->lfAlways(2);
-    fprintf(fOut, "#Subtopic %s_Member_Functions", className.c_str());
-    this->lfAlways(1);
-    fprintf(fOut, "#Table");
-    this->lfAlways(1);
-    fprintf(fOut, "#Legend");
-    this->lfAlways(1);
     maxLen = 0;
+    size_t constructorMax = 0;
+    size_t operatorMax = 0;
     vector<string> sortedNames;
+    vector<string> constructorNames;
+    vector<string> operatorNames;
     for (const auto& token : classMap.fTokens) {
         if (Definition::Type::kMark != token.fType || MarkType::kMethod != token.fMarkType) {
             continue;
         }
-        const string& name = token.fName;
+        string name = token.fName;
         if (name.substr(0, 7) == "android" || string::npos != name.find("nternal_")) {
             continue;
         }
+        if ((name.substr(0, 2) == "Sk" && 2 == name.find(className)) || '~' == name[0]) {
+            name = string(token.fContentStart, (int) (token.fContentEnd - token.fContentStart));
+            constructorMax = SkTMax(constructorMax, name.length());
+            constructorNames.emplace_back(name);
+            continue;
+        }
+        if (name.substr(0, 8) == "operator") {
+            name = string(token.fContentStart, (int) (token.fContentEnd - token.fContentStart));
+            operatorMax = SkTMax(operatorMax, name.length());
+            operatorNames.emplace_back(name);
+            continue;
+        }
         if (name[name.length() - 2] == '_' && isdigit(name[name.length() - 1])) {
             continue;
         }
+        if ("SK_TO_STRING_NONVIRT" == name) {
+            name = "toString";
+        }
         size_t paren = name.find('(');
         size_t funcLen = string::npos == paren ? name.length() : paren;
         maxLen = SkTMax(maxLen, funcLen);
         sortedNames.emplace_back(name);
     }
+    if (constructorMax) {
+        std::sort(constructorNames.begin(), constructorNames.end());
+        this->writeTag("Subtopic", "Constructors");
+        this->writeTableHeader("description", constructorMax, "function");
+        for (auto& name : constructorNames) {
+            this->writeTableRow(constructorMax, name);
+        }
+        this->writeTableTrailer();
+        this->writeEndTag("Subtopic");
+        this->lf(2);
+    }
+    if (operatorMax) {
+        std::sort(operatorNames.begin(), operatorNames.end());
+        this->writeTag("Subtopic", "Operators");
+        this->writeTableHeader("description", operatorMax, "function");
+        for (auto& name : operatorNames) {
+            this->writeTableRow(operatorMax, name);
+        }
+        this->writeTableTrailer();
+        this->writeEndTag("Subtopic");
+        this->lf(2);
+    }
     std::sort(sortedNames.begin(), sortedNames.end());
-    fprintf(fOut, "# %-*s # description   ##" "\n",
-            (int) maxLen, "function");
-    fprintf(fOut, "#Legend ##"                                                               "\n");
+    this->writeTag("Subtopic", "Member_Functions");
+    this->writeTableHeader("description", maxLen, "function");
     for (auto& name : sortedNames) {
         size_t paren = name.find('(');
         size_t funcLen = string::npos == paren ? name.length() : paren;
-        fprintf(fOut, "# %-*s # ##"                                                          "\n",
-                (int) maxLen, name.substr(0, funcLen).c_str());
+        this->writeTableRow(maxLen, name.substr(0, funcLen));
     }
-    fprintf(fOut, "#Table ##"                                                                "\n");
-    fprintf(fOut, "#Subtopic ##"                                                             "\n");
-    fprintf(fOut, ""                                                                         "\n");
-    fprintf(fOut, "#Topic ##"                                                                "\n");
-    fprintf(fOut, ""                                                                         "\n");
+    this->writeTableTrailer();
+    this->writeEndTag("Subtopic");
+    this->lf(2);
+    this->writeEndTag("Topic");
+    this->lf(2);
 
     for (auto& oneClass : fIClassMap) {
         if (skClassName + "::" != oneClass.first.substr(0, skClassName.length() + 2)) {
             continue;
         }
         string innerName = oneClass.first.substr(skClassName.length() + 2);
-        fprintf(fOut, "%s",
+        this->writeString(
             "# ------------------------------------------------------------------------------");
-        this->lfAlways(2);
-        fprintf(fOut, "#Struct %s", innerName.c_str());
-        this->lfAlways(2);
+        this->lf(2);
+        const char* containerType = kKeyWords[(int) oneClass.second.fKeyWord].fName;
+        this->writeTag(containerType, innerName);
+        this->lf(2);
+        this->writeTag("Code");
+        this->writeEndTag("ToDo", "fill this in manually");
+        this->writeEndTag();
+        this->lf(2);
         for (auto& token : oneClass.second.fTokens) {
             if (Definition::Type::kMark != token.fType || MarkType::kComment != token.fMarkType) {
                 continue;
             }
-            fprintf(fOut, "%.*s", (int) (token.fContentEnd - token.fContentStart),
-                    token.fContentStart);
-            this->lfAlways(1);
+            this->writeDefinition(token);
         }
         this->lf(2);
         this->dumpClassTokens(oneClass.second);
         this->lf(2);
-        fprintf(fOut, "#Struct %s ##", innerName.c_str());
-        this->lfAlways(2);
+        this->writeEndTag(containerType, innerName);
+        this->lf(2);
     }
     this->dumpClassTokens(classMap);
-    fprintf(fOut, "#Class %s ##"                                                             "\n",
-            skClassName.c_str());
-    fprintf(fOut, ""                                                                         "\n");
-    fprintf(fOut, "#Topic %s ##"                                                             "\n",
-            topicName.c_str());
+    this->writeEndTag(containerType, skClassName);
+    this->lf(2);
+    this->writeEndTag("Topic", topicName);
+    this->lfAlways(1);
     fclose(fOut);
     SkDebugf("wrote %s\n", fileName.c_str());
     return true;
@@ -859,9 +991,6 @@
 // caller calls reportError, so just return false here
 bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) {
     SkASSERT(includeDef->fTokens.size() > 0);
-    if (includeDef->fTokens.size() == 1) {
-        return true;  // forward declaration only
-    }
     // parse class header
     auto iter = includeDef->fTokens.begin();
     if (!strncmp(iter->fStart, "SK_API", iter->fContentEnd - iter->fStart)) {
@@ -870,24 +999,28 @@
     }
     string nameStr(iter->fStart, iter->fContentEnd - iter->fStart);
     includeDef->fName = nameStr;
+    iter = std::next(iter);
+    if (iter == includeDef->fTokens.end()) {
+        return true;  // forward declaration only
+    }
     do {
         if (iter == includeDef->fTokens.end()) {
-            return false;
+            return includeDef->reportError<bool>("unexpected end");
         }
         if ('{' == iter->fStart[0] && Definition::Type::kPunctuation == iter->fType) {
             break;
         }   
     } while (static_cast<void>(iter = std::next(iter)), true);
     if (Punctuation::kLeftBrace != iter->fPunctuation) {
-        return false;
+        return iter->reportError<bool>("expected left brace");
     }
     IClassDefinition* markupDef = this->defineClass(*includeDef, nameStr);
     if (!markupDef) {
-        return false;
+        return iter->reportError<bool>("expected markup definition");
     }
     markupDef->fStart = iter->fStart;
     if (!this->findComments(*includeDef, markupDef)) {
-        return false;
+        return iter->reportError<bool>("find comments failed");
     }
 //    if (1 != includeDef->fChildren.size()) {
 //        return false;  // fix me: SkCanvasClipVisitor isn't correctly parsed
@@ -1018,9 +1151,9 @@
     }
     TextParser parser(child);
     parser.skipToEndBracket('{');
+    parser.next();
     const char* dataEnd;
     do {
-        parser.next();
         parser.skipWhiteSpace();
         if ('}' == parser.peek()) {
             break;
@@ -1058,33 +1191,57 @@
         if ('}' == memberStart[0]) {
             break;
         }
+        // if there's comment on same the line as member def, output first as if it was before
+
         parser.skipToNonAlphaNum();
         string memberName(memberStart, parser.fChar);
-        parser.skipWhiteSpace();
+        if (parser.eof() || !parser.skipWhiteSpace()) {
+            return this->reportError<bool>("enum member must end with comma 1");
+        }
         const char* dataStart = parser.fChar;
-        SkASSERT('=' == dataStart[0] || ',' == dataStart[0] || '}' == dataStart[0]
-                 || '/' == dataStart[0]);
-        dataEnd = parser.anyOf(",}");
+        if ('=' == parser.peek()) {
+            parser.skipToEndBracket(',');
+        }
+        if (parser.eof() || ',' != parser.peek()) {
+            return this->reportError<bool>("enum member must end with comma 2");
+        }
+        dataEnd = parser.fChar;
+        const char* start = parser.anyOf("/\n");
+        SkASSERT(start);
+        parser.skipTo(start);
+        if ('/' == parser.next()) {
+            char slashStar = parser.next();
+            if ('/' == slashStar || '*' == slashStar) {
+                TextParser::Save save(&parser);
+                char doxCheck = parser.next();
+                if ((slashStar != doxCheck && '!' != doxCheck) || '<' != parser.next()) {
+                    save.restore();
+                }
+            }
+            parser.skipWhiteSpace();
+            const char* commentStart = parser.fChar;
+            if ('/' == slashStar) {
+                parser.skipToEndBracket('\n');
+            } else {
+                parser.skipToEndBracket("*/");
+            }
+            SkASSERT(!parser.eof());
+            const char* commentEnd = parser.fChar;
+            markupChild->fTokens.emplace_back(MarkType::kComment, commentStart, commentEnd,
+                    parser.fLineCount, markupChild);
+            comment = &markupChild->fTokens.back();
+            comment->fTerminator = commentEnd;
+        }
         markupChild->fTokens.emplace_back(MarkType::kMember, dataStart, dataEnd, parser.fLineCount,
                 markupChild);
         Definition* member = &markupChild->fTokens.back();
         member->fName = memberName;
         if (comment) {
             member->fChildren.push_back(comment);
+            comment->fPrivate = true;
         }
         markupChild->fChildren.push_back(member);
-        parser.skipToEndBracket(dataEnd[0]);
-    } while (',' == dataEnd[0]);
-    for (size_t index = 1; index < child->fChildren.size(); ++index) {
-        const Definition* follower = child->fChildren[index];
-        if (Definition::Type::kKeyWord == follower->fType) {
-            markupChild->fTokens.emplace_back(MarkType::kMember, follower->fContentStart, 
-                    follower->fContentEnd, follower->fLineCount, markupChild);
-            Definition* member = &markupChild->fTokens.back();
-            member->fName = follower->fName;
-            markupChild->fChildren.push_back(member);
-        }
-    }
+    } while (true);
     IClassDefinition& classDef = fIClassMap[markupDef->fName];
     SkASSERT(classDef.fStart);
     string uniqueName = this->uniqueName(classDef.fEnums, nameStr);
@@ -1125,6 +1282,7 @@
     IClassDefinition& classDef = fIClassMap[markupDef->fName];
     string uniqueName = this->uniqueName(classDef.fMethods, nameStr);
     markupChild->fName = uniqueName;
+    markupChild->fTerminator = markupChild->fContentEnd;
     classDef.fMembers[uniqueName] = markupChild;
     if (child->fParentIndex >= 2) {
         auto comment = child->fParent->fTokens.begin();
@@ -1162,6 +1320,9 @@
     std::advance(tokenIter, child->fParentIndex);
     tokenIter = std::prev(tokenIter);
     string nameStr(tokenIter->fStart, tokenIter->fContentEnd - tokenIter->fStart);
+    if (0 == nameStr.find("SK_ATTR_DEPRECATED")) {
+        SkDebugf("");
+    }
     while (tokenIter != child->fParent->fTokens.begin()) {
         auto testIter = std::prev(tokenIter);
         switch (testIter->fType) {
@@ -1231,6 +1392,17 @@
     while (end > start && ' ' >= end[-1]) {
         --end;
     }
+    if (!markupDef) {
+        auto parentIter = child->fParent->fTokens.begin();
+        SkASSERT(child->fParentIndex > 0);
+        std::advance(parentIter, child->fParentIndex - 1);
+        Definition* methodName = &*parentIter;
+        TextParser name(methodName);
+        if (name.skipToEndBracket(':') && name.startsWith("::")) {
+            return true;  // expect this is inline class definition outside of class
+        }
+        SkASSERT(0);  // code incomplete
+    }
     markupDef->fTokens.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount,
             markupDef);
     Definition* markupChild = &markupDef->fTokens.back();
@@ -1246,16 +1418,6 @@
     return true;
 }
 
-void IncludeParser::keywordEnd() {
-    fprintf(fOut, "##");
-    this->lfAlways(1);
-}
-
-void IncludeParser::keywordStart(const char* keyword) {
-    this->lf(1);
-    fprintf(fOut, "#%s ", keyword);
-}
-
 bool IncludeParser::parseObjects(Definition* parent, Definition* markupDef) {
     for (auto& child : parent->fChildren) {
         if (!this->parseObject(child, markupDef)) {
@@ -1275,36 +1437,36 @@
             switch (child->fKeyWord) {
                 case KeyWord::kClass: 
                     if (!this->parseClass(child, IsStruct::kNo)) {
-                        return this->reportError<bool>("failed to parse class");
+                        return false;
                     }
                     break;
                 case KeyWord::kEnum:
                     if (!this->parseEnum(child, markupDef)) {
-                        return this->reportError<bool>("failed to parse enum");
+                        return child->reportError<bool>("failed to parse enum");
                     }
                     break;
                 case KeyWord::kStruct:
                     if (!this->parseClass(child, IsStruct::kYes)) {
-                        return this->reportError<bool>("failed to parse struct");
+                        return child->reportError<bool>("failed to parse struct");
                     }
                     break;
                 case KeyWord::kTemplate:
                     if (!this->parseTemplate()) {
-                        return this->reportError<bool>("failed to parse template");
+                        return child->reportError<bool>("failed to parse template");
                     }
                     break;
                 case KeyWord::kTypedef:
                     if (!this->parseTypedef()) {
-                        return this->reportError<bool>("failed to parse typedef");
+                        return child->reportError<bool>("failed to parse typedef");
                     }
                     break;
                 case KeyWord::kUnion:
                     if (!this->parseUnion()) {
-                        return this->reportError<bool>("failed to parse union");
+                        return child->reportError<bool>("failed to parse union");
                     }
                     break;
                 default:
-                    return this->reportError<bool>("unhandled keyword");
+                    return child->reportError<bool>("unhandled keyword");
             }
             break;
         case Definition::Type::kBracket:
@@ -1313,13 +1475,24 @@
                     if (fLastObject) {
                         TextParser checkDeprecated(child->fFileName, fLastObject->fTerminator + 1,
                                 child->fStart, fLastObject->fLineCount);
-                        checkDeprecated.skipWhiteSpace();
+                        if (!checkDeprecated.eof()) {
+                            checkDeprecated.skipWhiteSpace();
+                            if (checkDeprecated.startsWith("SK_ATTR_DEPRECATED")) {
+                                break;
+                            }
+                        }
+                    }
+                    {
+                        auto tokenIter = child->fParent->fTokens.begin();
+                        std::advance(tokenIter, child->fParentIndex);
+                        tokenIter = std::prev(tokenIter);
+                        TextParser checkDeprecated(&*tokenIter);
                         if (checkDeprecated.startsWith("SK_ATTR_DEPRECATED")) {
                             break;
                         }
                     }
                     if (!this->parseMethod(child, markupDef)) {
-                        return this->reportError<bool>("failed to parse method");
+                        return child->reportError<bool>("failed to parse method");
                     }
                 break;
                 case Bracket::kSlashSlash:
@@ -1356,7 +1529,7 @@
                             break;
                         default:
                         preproError:
-                            return this->reportError<bool>("unhandled preprocessor");
+                            return child->reportError<bool>("unhandled preprocessor");
                     }
                     break;
                 case Bracket::kAngle:
@@ -1365,20 +1538,28 @@
                 case Bracket::kDebugCode:
                     // todo: handle this
                     break;
+                case Bracket::kSquare: {
+                    // check to see if parent is operator, the only case we handle so far
+                    auto prev = child->fParent->fTokens.begin();
+                    std::advance(prev, child->fParentIndex - 1);
+                    if (KeyWord::kOperator != prev->fKeyWord) {
+                        return child->reportError<bool>("expected operator overload");
+                    }
+                    } break;
                 default:
-                    return this->reportError<bool>("unhandled bracket");
+                    return child->reportError<bool>("unhandled bracket");
             }
             break;
         case Definition::Type::kWord:
             if (MarkType::kMember != child->fMarkType) {
-                return this->reportError<bool>("unhandled word type");
+                return child->reportError<bool>("unhandled word type");
             }
             if (!this->parseMember(child, markupDef)) {
-                return this->reportError<bool>("unparsable member");
+                return child->reportError<bool>("unparsable member");
             }
             break;
         default:
-            return this->reportError<bool>("unhandled type");
+            return child->reportError<bool>("unhandled type");
             break;
     }
     return true;
@@ -1679,6 +1860,9 @@
                     }
                     Definition* member = &*namedIter;
                     member->fMarkType = MarkType::kMember;
+                    if (!member->fTerminator) {
+                        member->fTerminator = member->fContentEnd;
+                    }
                     fParent->fChildren.push_back(member);
                     for (auto nameType = baseIter; nameType != namedIter; ++nameType) {
                         member->fChildren.push_back(&*nameType);