fix bookmaker nightly

- mark the interfaces that use SkMask as deprecated
- add more autogenerated subtopics
- make subtopic names singular, avoiding collision with Skia names
- simplify #Deprecated and #Bug tags
- add "#Deprecated soon" to note things to be deprecated
- fix some spelling errors
- refresh web docs
- add self-check functionality to find methods outside subtopics

TBR=caryclark@google.com
Docs-Preview: https://skia.org/?cl=102150
Bug: skia:6898
Change-Id: I0e742a56d49dccd4409bb68eed9167c8ad7611ce
Reviewed-on: https://skia-review.googlesource.com/102150
Commit-Queue: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index 0de8a46..9d5a278 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -248,7 +248,6 @@
         case MarkType::kDescription:
         case MarkType::kStdOut:
         // may be one-liner
-        case MarkType::kBug:
         case MarkType::kNoExample:
         case MarkType::kParam:
         case MarkType::kReturn:
@@ -285,7 +284,6 @@
             }
         // not one-liners
         case MarkType::kCode:
-        case MarkType::kDeprecated:
         case MarkType::kExample:
         case MarkType::kExperimental:
         case MarkType::kFormula:
@@ -344,7 +342,9 @@
             // always treated as one-liners (can't detect misuse easily)
         case MarkType::kAlias:
         case MarkType::kAnchor:
+        case MarkType::kBug:
         case MarkType::kDefine:
+        case MarkType::kDeprecated:
         case MarkType::kDuration:
         case MarkType::kFile:
         case MarkType::kHeight:
@@ -361,6 +361,7 @@
         case MarkType::kTime:
         case MarkType::kVolatile:
         case MarkType::kWidth:
+            // todo : add check disallowing children?
             if (hasEnd && MarkType::kAnchor != markType && MarkType::kLine != markType) {
                 return this->reportError<bool>("one liners omit end element");
             } else if (!hasEnd && MarkType::kAnchor == markType) {
@@ -415,7 +416,15 @@
 				definition->fContentEnd = text->fContentEnd;
 				definition->fTerminator = fChar;
 				definition->fChildren.emplace_back(text);
-			}
+			} else if (MarkType::kDeprecated == markType) {
+                 this->skipSpace();
+                 fParent->fDeprecated = true;
+                 fParent->fToBeDeprecated = this->skipExact("soon");
+                 this->skipSpace();
+                 if ('\n' != this->peek()) {
+                     return this->reportError<bool>("unexpected text after #Deprecated");
+                 }
+            }
             break;
         case MarkType::kExternal:
             (void) this->collectExternals();  // FIXME: detect errors in external defs?
@@ -1250,6 +1259,20 @@
         definition->fLineCount) {
 }
 
+string TextParser::ReportFilename(string file) {
+	string fullName;
+#ifdef SK_BUILD_FOR_WIN
+	TCHAR pathChars[MAX_PATH];
+	DWORD pathLen = GetCurrentDirectory(MAX_PATH, pathChars);
+	for (DWORD index = 0; index < pathLen; ++index) {
+		fullName += pathChars[index] == (char)pathChars[index] ? (char)pathChars[index] : '?';
+	}
+	fullName += '\\';
+#endif
+	fullName += file;
+    return fullName;
+}
+
 void TextParser::reportError(const char* errorStr) const {
     this->reportWarning(errorStr);
     SkDebugf("");  // convenient place to set a breakpoint
@@ -1265,17 +1288,8 @@
         spaces -= lineLen;
         lineLen = err.lineLength();
     }
-	string fileName;
-#ifdef SK_BUILD_FOR_WIN
-	TCHAR pathChars[MAX_PATH];
-	DWORD pathLen = GetCurrentDirectory(MAX_PATH, pathChars);
-	for (DWORD index = 0; index < pathLen; ++index) {
-		fileName += pathChars[index] == (char)pathChars[index] ? (char)pathChars[index] : '?';
-	}
-	fileName += '\\';
-#endif
-	fileName += fFileName;
-    SkDebugf("\n%s(%zd): error: %s\n", fileName.c_str(), err.fLineCount, errorStr);
+	string fullName = this->ReportFilename(fFileName);
+    SkDebugf("\n%s(%zd): error: %s\n", fullName.c_str(), err.fLineCount, errorStr);
     if (0 == lineLen) {
         SkDebugf("[blank line]\n");
     } else {
@@ -1476,7 +1490,6 @@
             this->skipNoName();
             break;
         case MarkType::kCode:
-        case MarkType::kDeprecated:
         case MarkType::kDescription:
         case MarkType::kDoxygen:
         case MarkType::kExperimental:
@@ -1498,6 +1511,7 @@
         case MarkType::kBug:  // fixme: expect number
         case MarkType::kDefine:
         case MarkType::kDefinedBy:
+        case MarkType::kDeprecated:
         case MarkType::kDuration:
         case MarkType::kFile:
         case MarkType::kHeight:
diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h
index 65e8f15..9637275 100644
--- a/tools/bookmaker/bookmaker.h
+++ b/tools/bookmaker/bookmaker.h
@@ -390,6 +390,7 @@
     }
 
     void reportError(const char* errorStr) const;
+    static string ReportFilename(string file);
     void reportWarning(const char* errorStr) const;
 
     template <typename T> T reportError(const char* errorStr) const {
@@ -841,6 +842,7 @@
     bool exampleToScript(string* result, ExampleOptions ) const;
     string extractText(TrimExtract trimExtract) const;
     string fiddleName() const;
+    const Definition* findClone(string match) const;
     string formatFunction() const;
     const Definition* hasChild(MarkType markType) const;
     bool hasMatch(const string& name) const;
@@ -919,9 +921,11 @@
     Type fType = Type::kNone;
     bool fClone = false;
     bool fCloned = false;
+    bool fDeprecated = false;
     bool fOperatorConst = false;
     bool fPrivate = false;
     bool fShort = false;
+    bool fToBeDeprecated = false;
     bool fMemberStart = false;
     bool fAnonymous = false;
     mutable bool fVisited = false;
@@ -2034,15 +2038,15 @@
     bool buildReferences(const char* docDir, const char* mdOutDirOrFile);
     bool buildStatus(const char* docDir, const char* mdOutDir);
 
-    static constexpr const char* kClassesAndStructs = "Classes_and_Structs";
-    static constexpr const char* kConstants = "Constants";
-    static constexpr const char* kConstructors = "Constructors";
-    static constexpr const char* kMemberFunctions = "Member_Functions";
-    static constexpr const char* kMembers = "Members";
-    static constexpr const char* kOperators = "Operators";
+    static constexpr const char* kClassesAndStructs = "Class_or_Struct";
+    static constexpr const char* kConstants = "Constant";
+    static constexpr const char* kConstructors = "Constructor";
+    static constexpr const char* kMemberFunctions = "Member_Function";
+    static constexpr const char* kMembers = "Member";
+    static constexpr const char* kOperators = "Operator";
     static constexpr const char* kOverview = "Overview";
-    static constexpr const char* kRelatedFunctions = "Related_Functions";
-    static constexpr const char* kSubtopics = "Subtopics";
+    static constexpr const char* kRelatedFunctions = "Related_Function";
+    static constexpr const char* kSubtopics = "Subtopic";
 
 private:
     enum class TableState {
@@ -2051,6 +2055,16 @@
         kColumn,
     };
 
+    struct TableContents {
+        TableContents()
+            : fShowClones(false) {
+        }
+
+        string fDescription;
+        vector<const Definition*> fMembers;
+        bool fShowClones;
+    };
+
     string addReferences(const char* start, const char* end, BmhParser::Resolvable );
     bool buildRefFromFile(const char* fileName, const char* outDir);
     bool checkParamReturnBody(const Definition* def) const;
@@ -2068,8 +2082,11 @@
     bool parseFromFile(const char* path) override { return true; }
     void populateTables(const Definition* def);
 
-    vector<const Definition*>& populator(const char* key) {
-        return fPopulators.find(key)->second.fMembers;
+    TableContents& populator(const char* key) {
+        auto entry = fPopulators.find(key);
+        // FIXME: this should have been detected earlier
+        SkASSERT(fPopulators.end() != entry);
+        return entry->second;
     }
 
     void reset() override {
@@ -2103,14 +2120,9 @@
 
     void resolveOut(const char* start, const char* end, BmhParser::Resolvable );
     void rowOut(const char * name, const string& description);
-    void subtopicOut(vector<const Definition*>& data);
+    void subtopicOut(const TableContents& tableContents);
     void subtopicsOut();
 
-    struct TableContents {
-        string fDescription;
-        vector<const Definition*> fMembers;
-    };
-
     unordered_map<string, TableContents> fPopulators;
     vector<const Definition*> fClassStack;
 
diff --git a/tools/bookmaker/definition.cpp b/tools/bookmaker/definition.cpp
index 7885c63..757169b 100644
--- a/tools/bookmaker/definition.cpp
+++ b/tools/bookmaker/definition.cpp
@@ -560,6 +560,7 @@
                 break;
             case MarkType::kToDo:
                 break;
+            case MarkType::kBug:
             case MarkType::kMarkChar:
             case MarkType::kPlatform:
                 // ignore for now
@@ -1014,6 +1015,22 @@
     return fFiddle.substr(start, end - start);
 }
 
+const Definition* Definition::findClone(string match) const {
+    for (auto child : fChildren) {
+        if (!child->fClone) {
+            continue;
+        }
+        if (match == child->fName) {
+            return child;
+        }
+        auto inner = child->findClone(match);
+        if (inner) {
+            return inner;
+        }
+    }
+    return nullptr;
+}
+
 const Definition* Definition::hasChild(MarkType markType) const {
     for (auto iter : fChildren) {
         if (markType == iter->fMarkType) {
diff --git a/tools/bookmaker/includeWriter.cpp b/tools/bookmaker/includeWriter.cpp
index ba93d3e..77baca0 100644
--- a/tools/bookmaker/includeWriter.cpp
+++ b/tools/bookmaker/includeWriter.cpp
@@ -53,6 +53,13 @@
                 commentStart = prop->fTerminator;
                 break;
             case MarkType::kDeprecated:
+                SkASSERT(def->fDeprecated);
+                if (def->fToBeDeprecated) {
+                    this->writeString("To be deprecated soon.");
+                } else {
+                    this->writeString("Deprecated.");
+                }
+                this->lfcr();
             case MarkType::kPrivate:
                 commentLen = (int) (prop->fStart - commentStart);
                 if (commentLen > 0) {
@@ -62,6 +69,9 @@
                     }
                 }
                 commentStart = prop->fContentStart;
+                if (def->fToBeDeprecated) {
+                    commentStart += 4; // skip over "soon" // FIXME: this is awkward
+                }
                 commentLen = (int) (prop->fContentEnd - commentStart);
                 if (commentLen > 0) {
                     this->writeBlockIndent(commentLen, commentStart);
@@ -159,7 +169,7 @@
             break;
         }
     }
-    SkASSERT(wroteCode || (commentLen > 0 && commentLen < 1500));
+    SkASSERT(wroteCode || (commentLen > 0 && commentLen < 1500) || def->fDeprecated);
     if (commentLen > 0) {
         this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
     }
@@ -440,23 +450,35 @@
             commentEnd = currentEnumItem->fContentEnd;
         }
         TextParser enumComment(fFileName, commentStart, commentEnd, currentEnumItem->fLineCount);
+        bool isDeprecated = false;
         if (enumComment.skipToLineStart()) {  // skip const value
             commentStart = enumComment.fChar;
             commentLen = (int) (commentEnd - commentStart);
         } else {
-            const Definition* privateDef = currentEnumItem->fChildren[0];
-            SkASSERT(MarkType::kPrivate == privateDef->fMarkType);
-            commentStart = privateDef->fContentStart;
-            commentLen = (int) (privateDef->fContentEnd - privateDef->fContentStart);
+            const Definition* childDef = currentEnumItem->fChildren[0];
+            isDeprecated = MarkType::kDeprecated == childDef->fMarkType;
+            if (MarkType::kPrivate == childDef->fMarkType || isDeprecated) {
+                commentStart = childDef->fContentStart;
+                if (currentEnumItem->fToBeDeprecated) {
+                    SkASSERT(isDeprecated);
+                    commentStart += 4; // skip over "soon" // FIXME: this is awkward
+                }
+                commentLen = (int) (childDef->fContentEnd - commentStart);
+            }
         }
         // FIXME: may assert here if there's no const value
         // should have detected and errored on that earlier when enum fContentStart was set
-        SkASSERT(commentLen > 0 && commentLen < 1000);
+        SkASSERT((commentLen > 0 && commentLen < 1000) || isDeprecated);
         if (!currentEnumItem->fShort) {
             this->writeCommentHeader();
             fIndent += 4;
-            bool wroteLineFeed = Wrote::kLF ==
-                    this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
+            bool wroteLineFeed = false;
+            if (isDeprecated) {
+                this->writeString(currentEnumItem->fToBeDeprecated
+                        ? "To be deprecated soon." : "Deprecated.");
+            }
+            wroteLineFeed  = Wrote::kLF ==
+                this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
             fIndent -= 4;
             if (wroteLineFeed || fColumn > 100 - 3 /* space * / */ ) {
                 this->lfcr();
diff --git a/tools/bookmaker/mdOut.cpp b/tools/bookmaker/mdOut.cpp
index b51bb8d..7bc70af 100644
--- a/tools/bookmaker/mdOut.cpp
+++ b/tools/bookmaker/mdOut.cpp
@@ -975,9 +975,6 @@
             if (kSubtopics == name) {
                 this->subtopicsOut();
             } else {
-                SkASSERT(kClassesAndStructs == name || kConstants == name || kConstructors == name
-                        || kMemberFunctions == name || kMembers == name || kOperators == name
-                        || kRelatedFunctions == name);
                 this->subtopicOut(this->populator(name.c_str()));
             }
             } break;
@@ -1187,17 +1184,20 @@
 void MdOut::populateTables(const Definition* def) {
     const Definition* csParent = this->csParent();
     for (auto child : def->fChildren) {
+        if (string::npos != child->fName.find("Rect_Set")) {
+            SkDebugf("");
+        }
         if (MarkType::kTopic == child->fMarkType || MarkType::kSubtopic == child->fMarkType) {
             bool legacyTopic = fPopulators.end() != fPopulators.find(child->fName);
             if (!legacyTopic && child->fName != kOverview) {
-                this->populator(kRelatedFunctions).push_back(child);
+                this->populator(kRelatedFunctions).fMembers.push_back(child);
             }
             this->populateTables(child);
             continue;
         }
         if (child->isStructOrClass()) {
             if (fClassStack.size() > 0) {
-                this->populator(kClassesAndStructs).push_back(child);
+                this->populator(kClassesAndStructs).fMembers.push_back(child);
             }
             fClassStack.push_back(child);
             this->populateTables(child);
@@ -1205,11 +1205,11 @@
             continue;
         }
         if (MarkType::kEnum == child->fMarkType || MarkType::kEnumClass == child->fMarkType) {
-            this->populator(kConstants).push_back(child);
+            this->populator(kConstants).fMembers.push_back(child);
             continue;
         }
         if (MarkType::kMember == child->fMarkType) {
-            this->populator(kMembers).push_back(child);
+            this->populator(kMembers).fMembers.push_back(child);
             continue;
         }
         if (MarkType::kMethod != child->fMarkType) {
@@ -1220,17 +1220,26 @@
         }
         if (Definition::MethodType::kConstructor == child->fMethodType
                 || Definition::MethodType::kDestructor == child->fMethodType) {
-            this->populator(kConstructors).push_back(child);
+            this->populator(kConstructors).fMembers.push_back(child);
             continue;
         }
         if (Definition::MethodType::kOperator == child->fMethodType) {
-            this->populator(kOperators).push_back(child);
+            this->populator(kOperators).fMembers.push_back(child);
             continue;
         }
-        this->populator(kMemberFunctions).push_back(child);
+        this->populator(kMemberFunctions).fMembers.push_back(child);
         if (csParent && (0 == child->fName.find(csParent->fName + "::Make")
                 || 0 == child->fName.find(csParent->fName + "::make"))) {
-            this->populator(kConstructors).push_back(child);
+            this->populator(kConstructors).fMembers.push_back(child);
+            continue;
+        }
+        for (auto item : child->fChildren) {
+            if (MarkType::kIn == item->fMarkType) {
+                string name(item->fContentStart, item->fContentEnd - item->fContentStart);
+                fPopulators[name].fMembers.push_back(child);
+                fPopulators[name].fShowClones = true;
+                break;
+            }
         }
     }
 }
@@ -1331,7 +1340,7 @@
     this->rowOut("---", "---");
     for (auto item : { kClassesAndStructs, kConstants, kConstructors, kMemberFunctions,
             kMembers, kOperators, kRelatedFunctions } ) {
-        for (auto entry : this->populator(item)) {
+        for (auto entry : this->populator(item).fMembers) {
             if (entry->csParent() == csParent) {
                 string description = fPopulators.find(item)->second.fDescription;
                 if (kConstructors == item) {
@@ -1344,7 +1353,8 @@
     }
 }
 
-void MdOut::subtopicOut(vector<const Definition*>& data) {
+void MdOut::subtopicOut(const TableContents& tableContents) {
+    const auto& data = tableContents.fMembers;
     const Definition* csParent = this->csParent();
     SkASSERT(csParent);
     fRoot = csParent->asRoot();
@@ -1360,6 +1370,9 @@
         items[name] = entry;
     }
     for (auto entry : items) {
+        if (entry.second->fDeprecated) {
+            continue;
+        }
         const Definition* oneLiner = nullptr;
         for (auto child : entry.second->fChildren) {
             if (MarkType::kLine == child->fMarkType) {
@@ -1367,8 +1380,30 @@
                 break;
             }
         }
+        if (!oneLiner) {
+            SkDebugf("");
+        }
         SkASSERT(oneLiner);
         this->rowOut(entry.first.c_str(), string(oneLiner->fContentStart,
             oneLiner->fContentEnd - oneLiner->fContentStart));
+        if (string::npos != entry.second->fName.find("SkRect::set")) {
+            SkDebugf("");
+        }
+        if (tableContents.fShowClones && entry.second->fCloned) {
+            int cloneNo = 2;
+            string builder = entry.second->fName;
+            if ("()" == builder.substr(builder.length() - 2)) {
+                builder = builder.substr(0, builder.length() - 2);
+            }
+            builder += '_';
+            do {
+                string match = builder + to_string(cloneNo);
+                auto child = csParent->findClone(match);
+                if (!child) {
+                    break;
+                }
+                this->rowOut("", child->methodName());
+            } while (++cloneNo);
+        }
     }
 }
diff --git a/tools/bookmaker/selfCheck.cpp b/tools/bookmaker/selfCheck.cpp
index fd8ef59..3392945 100644
--- a/tools/bookmaker/selfCheck.cpp
+++ b/tools/bookmaker/selfCheck.cpp
@@ -7,11 +7,12 @@
 
 #include "bookmaker.h"
 
+#ifdef SK_BUILD_FOR_WIN
+#include <windows.h>
+#endif
 
 // Check that mutiple like-named methods are under one Subtopic
 
-// Check that all subtopics are in table of contents
-
 // Check that SeeAlso reference each other
 
 // Would be nice to check if other classes have 'create' methods that are included
@@ -33,27 +34,10 @@
                 return fBmhParser.reportError<bool>("expected root topic");
             }
             fRoot = topicDef->asRoot();
-            if (!this->checkMethodSummary()) {
-                return false;
-            }
-            if (!this->checkMethodSubtopic()) {
-                return false;
-            }
-            if (!this->checkSubtopicSummary()) {
-                return false;
-            }
-            if (!this->checkConstructorsSummary()) {
-                return false;
-            }
-            if (!this->checkOperatorsSummary()) {
-                return false;
-            }
             if (!this->checkSeeAlso()) {
                 return false;
             }
-            if (!this->checkCreators()) {
-                return false;
-            }
+            // report functions that are not covered by related hierarchy
 			if (!this->checkRelatedFunctions()) {
 				return false;
 			}
@@ -62,164 +46,8 @@
     }
 
 protected:
-    // Check that all constructors are in a table of contents
-    //          should be 'creators' instead of constructors?
-    bool checkConstructorsSummary() {
-        for (auto& rootChild : fRoot->fChildren) {
-            if (!rootChild->isStructOrClass()) {
-                continue;
-            }
-            auto& cs = rootChild;
-			auto constructors = this->findTopic("Constructors", Optional::kYes);
-			if (constructors && MarkType::kSubtopic != constructors->fMarkType) {
-                return constructors->reportError<bool>("expected #Subtopic Constructors");
-            }
-            vector<string> constructorEntries;
-            if (constructors) {
-                if (!this->collectEntries(constructors, &constructorEntries)) {
-                    return false;
-                }
-            }
-            // mark corresponding methods as visited (may be more than one per entry)
-            for (auto& csChild : cs->fChildren) {
-                if (MarkType::kMethod != csChild->fMarkType) {
-                    // only check methods for now
-                    continue;
-                }
-                string name;
-                if (!this->childName(csChild, &name)) {
-                    return false;
-                }
-                string returnType;
-                if (Definition::MethodType::kConstructor != csChild->fMethodType &&
-                        Definition::MethodType::kDestructor != csChild->fMethodType) {
-                    string makeCheck = name.substr(0, 4);
-                    if ("Make" != makeCheck && "make" != makeCheck) {
-                        continue;
-                    }
-                    // for now, assume return type of interest is first word to start Sk
-                    string search(csChild->fStart, csChild->fContentStart - csChild->fStart);
-                    auto end = search.find(makeCheck);
-                    if (string::npos == end) {
-                        return csChild->reportError<bool>("expected Make in content");
-                    }
-                    search = search.substr(0, end);
-                    if (string::npos == search.find(cs->fName)) {
-                        // if return value doesn't match current struct or class, look in
-                        // returned struct / class instead
-                        auto sk = search.find("Sk");
-                        if (string::npos != sk) {
-                            // todo: build class name, find it, search for match in its overview
-                            continue;
-                        }
-                    }
-                }
-                if (constructorEntries.end() ==
-                        std::find(constructorEntries.begin(), constructorEntries.end(), name)) {
-                    return csChild->reportError<bool>("missing constructor in Constructors");
-                }
-            }
-        }
-        return true;
-    }
-
-    bool checkCreators() {
-        return true;
-    }
-
-    bool checkMethodSubtopic() {
-        return true;
-    }
-
-    // Check that summary contains all methods
-    bool checkMethodSummary() {
-        // look for struct or class in fChildren
-		const Definition* cs = this->classOrStruct();
-		if (!cs) {
-			return true;  // topics may not have included classes or structs
-		}
-		auto memberFunctions = this->findTopic("Member_Functions", Optional::kNo);
-        if (MarkType::kSubtopic != memberFunctions->fMarkType) {
-            return memberFunctions->reportError<bool>("expected #Subtopic Member_Functions");
-        }
-        vector<string> methodEntries; // build map of overview entries
-        if (!this->collectEntries(memberFunctions, &methodEntries)) {
-            return false;
-        }
-        // mark corresponding methods as visited (may be more than one per entry)
-        for (auto& csChild : cs->fChildren) {
-            if (MarkType::kMethod != csChild->fMarkType) {
-                // only check methods for now
-                continue;
-            }
-            if (Definition::MethodType::kConstructor == csChild->fMethodType) {
-                continue;
-            }
-            if (Definition::MethodType::kDestructor == csChild->fMethodType) {
-                continue;
-            }
-            if (Definition::MethodType::kOperator == csChild->fMethodType) {
-                continue;
-            }
-            string name;
-            if (!this->childName(csChild, &name)) {
-                return false;
-            }
-            if (methodEntries.end() ==
-                    std::find(methodEntries.begin(), methodEntries.end(), name)) {
-                return csChild->reportError<bool>("missing method in Member_Functions");
-            }
-        }
-        return true;
-    }
-
-    // Check that all operators are in a table of contents
-    bool checkOperatorsSummary() {
-		const Definition* cs = this->classOrStruct();
-		if (!cs) {
-			return true;  // topics may not have included classes or structs
-		}
-        const Definition* operators = this->findTopic("Operators", Optional::kYes);
-        if (operators && MarkType::kSubtopic != operators->fMarkType) {
-            return operators->reportError<bool>("expected #Subtopic Operators");
-        }
-        vector<string> operatorEntries;
-        if (operators) {
-            if (!this->collectEntries(operators, &operatorEntries)) {
-                return false;
-            }
-        }
-        for (auto& csChild : cs->fChildren) {
-            if (Definition::MethodType::kOperator != csChild->fMethodType) {
-                continue;
-            }
-            string name;
-            if (!this->childName(csChild, &name)) {
-                return false;
-            }
-            bool found = false;
-            for (auto str : operatorEntries) {
-                if (string::npos != str.find(name)) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                return csChild->reportError<bool>("missing operator in Operators");
-            }
-        }
-        return true;
-    }
 
 	bool checkRelatedFunctions() {
-		auto related = this->findTopic("Related_Functions", Optional::kYes);
-		if (!related) {
-			return true;
-		}
-		vector<string> relatedEntries;
-		if (!this->collectEntries(related, &relatedEntries)) {
-			return false;
-		}
 		const Definition* cs = this->classOrStruct();
 		vector<string> methodNames;
 		if (cs) {
@@ -243,36 +71,28 @@
 					// since format of clones is in flux, defer this check for now
 					continue;
 				}
-
-				SkASSERT(string::npos != csChild->fName.find(prefix));
-				string name = csChild->fName.substr(csChild->fName.find(prefix));
-				methodNames.push_back(name);
+                bool containsMarkTypeIn = csChild->fDeprecated;  // no markup for deprecated
+                for (auto child : csChild->fChildren) {
+                    if (MarkType::kIn == child->fMarkType) {
+                        containsMarkTypeIn = true;
+                        break;
+                    }
+                }
+                if (!containsMarkTypeIn) {
+#ifdef SK_BUILD_FOR_WIN
+                    /* SkDebugf works in both visual studio and git shell, but
+                       in git shell output is not piped to grep.
+                       printf does not generate output in visual studio, but
+                       does in git shell and can be piped.
+                     */
+                    if (IsDebuggerPresent()) {
+                        SkDebugf("No #In: %s\n", csChild->fName.c_str());
+                    } else
+#endif
+                    printf("No #In: %s\n", csChild->fName.c_str());
+                }
 			}
 		}
-		vector<string> trim = methodNames;
-		for (auto entryName : relatedEntries) {
-			auto entryDef = this->findTopic(entryName, Optional::kNo);
-			if (!entryDef) {
-
-			}
-			vector<string> entries;
-			this->collectEntries(entryDef, &entries);
-			for (auto entry : entries) {
-				auto it = std::find(methodNames.begin(), methodNames.end(), entry);
-				if (it == methodNames.end()) {
-					return cs->reportError<bool>("missing method");
-				}
-				it = std::find(trim.begin(), trim.end(), entry);
-				if (it != trim.end()) {
-					using std::swap;
-					swap(*it, trim.back());
-					trim.pop_back();
-				}
-			}
-		}
-		if (trim.size() > 0) {
-			return cs->reportError<bool>("extra method");
-		}
 		return true;
 	}
 
@@ -280,81 +100,6 @@
         return true;
     }
 
-    bool checkSubtopicSummary() {
-        const auto& cs = this->classOrStruct();
-		if (!cs) {
-			return true;
-		}
-        auto overview = this->findOverview(cs);
-        if (!overview) {
-            return false;
-        }
-        const Definition* subtopics = this->findTopic("Subtopics", Optional::kNo);
-        if (MarkType::kSubtopic != subtopics->fMarkType) {
-            return subtopics->reportError<bool>("expected #Subtopic Subtopics");
-        }
-		const Definition* relatedFunctions = this->findTopic("Related_Functions", Optional::kYes);
-		if (relatedFunctions && MarkType::kSubtopic != relatedFunctions->fMarkType) {
-            return relatedFunctions->reportError<bool>("expected #Subtopic Related_Functions");
-        }
-        vector<string> subtopicEntries;
-        if (!this->collectEntries(subtopics, &subtopicEntries)) {
-            return false;
-        }
-        if (relatedFunctions && !this->collectEntries(relatedFunctions, &subtopicEntries)) {
-            return false;
-        }
-        for (auto& csChild : cs->fChildren) {
-            if (MarkType::kSubtopic != csChild->fMarkType) {
-                continue;
-            }
-            string name;
-            if (!this->childName(csChild, &name)) {
-                return false;
-            }
-            bool found = false;
-            for (auto str : subtopicEntries) {
-                if (string::npos != str.find(name)) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                return csChild->reportError<bool>("missing SubTopic in SubTopics");
-            }
-        }
-        return true;
-    }
-
-    bool childName(const Definition* def, string* name) {
-        auto start = def->fName.find_last_of(':');
-        start = string::npos == start ? 0 : start + 1;
-        *name = def->fName.substr(start);
-        if (def->fClone) {
-            auto lastUnderline = name->find_last_of('_');
-            if (string::npos == lastUnderline) {
-                return def->reportError<bool>("expect _ in name");
-            }
-            if (lastUnderline + 1 >= name->length()) {
-                return def->reportError<bool>("expect char after _ in name");
-            }
-            for (auto index = lastUnderline + 1; index < name->length(); ++index) {
-                if (!isdigit((*name)[index])) {
-                    return def->reportError<bool>("expect digit after _ in name");
-                }
-            }
-            *name = name->substr(0, lastUnderline);
-            bool allLower = true;
-            for (auto ch : *name) {
-                allLower &= (bool) islower(ch);
-            }
-            if (allLower) {
-                *name += "()";
-            }
-        }
-        return true;
-    }
-
 	const Definition* classOrStruct() {
 		for (auto& rootChild : fRoot->fChildren) {
 			if (rootChild->isStructOrClass()) {
@@ -364,102 +109,11 @@
 		return nullptr;
 	}
 
-	static const Definition* overview_def(const Definition* parent) {
-		Definition* overview = nullptr;
-		if (parent) {
-			for (auto& csChild : parent->fChildren) {
-				if ("Overview" == csChild->fName) {
-					if (overview) {
-						return csChild->reportError<const Definition*>("expected only one Overview");
-					}
-					overview = csChild;
-				}
-			}
-		}
-		return overview;
-	}
-
-    const Definition* findOverview(const Definition* parent) {
-        // expect Overview as Topic in every main class or struct
-        const Definition* overview = overview_def(parent);
-		const Definition* parentOverview = parent ? overview_def(parent->fParent) : nullptr;
-		if (overview && parentOverview) {
-			return overview->reportError<const Definition*>("expected only one Overview 2");
-		}
-		overview = overview ? overview : parentOverview;
-        if (!overview) {
-            return parent->reportError<const Definition*>("missing #Topic Overview");
-        }
-        return overview;
-    }
-
 	enum class Optional {
 		kNo,
 		kYes,
 	};
 
-	const Definition* findTopic(string name, Optional optional) {
-		string undashed = name;
-		std::replace(undashed.begin(), undashed.end(), '-', '_');
-		string topicKey = fRoot->fName + '_' + undashed;
-		auto topicKeyIter = fBmhParser.fTopicMap.find(topicKey);
-		if (fBmhParser.fTopicMap.end() == topicKeyIter) {
-			// TODO: remove this and require member functions outside of overview
-			topicKey = fRoot->fName + "_Overview_" + undashed;  // legacy form for now
-			topicKeyIter = fBmhParser.fTopicMap.find(topicKey);
-			if (fBmhParser.fTopicMap.end() == topicKeyIter) {
-				if (Optional::kNo == optional) {
-					return fRoot->reportError<Definition*>("missing subtopic");
-				}
-				return nullptr;
-			}
-		}
-		return topicKeyIter->second;
-	}
-
-    bool collectEntries(const Definition* entries, vector<string>* strings) {
-        const Definition* table = nullptr;
-        for (auto& child : entries->fChildren) {
-            if (MarkType::kTable == child->fMarkType && child->fName == entries->fName) {
-                table = child;
-                break;
-            }
-        }
-        if (!table) {
-            return entries->reportError<bool>("missing #Table in Overview Subtopic");
-        }
-        bool expectLegend = true;
-        string prior = " ";  // expect entries to be alphabetical
-        for (auto& row : table->fChildren) {
-            if (MarkType::kLegend == row->fMarkType) {
-                if (!expectLegend) {
-                    return row->reportError<bool>("expect #Legend only once");
-                }
-                // todo: check if legend format matches table's rows' format
-                expectLegend = false;
-            } else if (expectLegend) {
-                return row->reportError<bool>("expect #Legend first");
-            }
-            if (MarkType::kRow != row->fMarkType) {
-                continue;  // let anything through for now; can tighten up in the future
-            }
-            // expect column 0 to point to function name
-            Definition* column0 = row->fChildren[0];
-            string name = string(column0->fContentStart,
-                    column0->fContentEnd - column0->fContentStart);
-            if (prior > name) {
-                return row->reportError<bool>("expect alphabetical order");
-            }
-            if (prior == name) {
-                return row->reportError<bool>("expect unique names");
-            }
-            // todo: error if name is all lower case and doesn't end in ()
-            strings->push_back(name);
-            prior = name;
-        }
-        return true;
-    }
-
 private:
     const BmhParser& fBmhParser;
     RootDefinition* fRoot;
diff --git a/tools/bookmaker/spellCheck.cpp b/tools/bookmaker/spellCheck.cpp
index 0daa460..efc79ca 100644
--- a/tools/bookmaker/spellCheck.cpp
+++ b/tools/bookmaker/spellCheck.cpp
@@ -53,7 +53,6 @@
         INHERITED::resetCommon();
         fMethod = nullptr;
         fRoot = nullptr;
-        fTableState = TableState::kNone;
         fInCode = false;
         fInConst = false;
         fInFormula = false;
@@ -74,7 +73,7 @@
     const BmhParser& fBmhParser;
     Definition* fMethod;
     RootDefinition* fRoot;
-    TableState fTableState;
+    int fLocalLine;
     bool fInCode;
     bool fInConst;
     bool fInDescription;
@@ -136,10 +135,6 @@
     fLineCount = def->fLineCount;
     string printable = def->printableName();
     const char* textStart = def->fContentStart;
-    if (MarkType::kParam != def->fMarkType && MarkType::kConst != def->fMarkType &&
-            MarkType::kPrivate != def->fMarkType && TableState::kNone != fTableState) {
-        fTableState = TableState::kNone;
-    }
     switch (def->fMarkType) {
         case MarkType::kAlias:
             break;
@@ -159,12 +154,6 @@
             break;
         case MarkType::kConst: {
             fInConst = true;
-            if (TableState::kNone == fTableState) {
-                fTableState = TableState::kRow;
-            }
-            if (TableState::kRow == fTableState) {
-                fTableState = TableState::kColumn;
-            }
             this->wordCheck(def->fName);
             const char* lineEnd = strchr(textStart, '\n');
             this->wordCheck(lineEnd - textStart, textStart);
@@ -204,8 +193,12 @@
             break;
         case MarkType::kImage:
             break;
+        case MarkType::kIn:
+            break;
         case MarkType::kLegend:
             break;
+        case MarkType::kLine:
+            break;
         case MarkType::kLink:
             break;
         case MarkType::kList:
@@ -225,7 +218,6 @@
             if (!def->isClone() && Definition::MethodType::kOperator != def->fMethodType) {
                 this->wordCheck(method_name);
             }
-            fTableState = TableState::kNone;
             fMethod = def;
             } break;
         case MarkType::kNoExample:
@@ -233,12 +225,6 @@
         case MarkType::kOutdent:
             break;
         case MarkType::kParam: {
-            if (TableState::kNone == fTableState) {
-                fTableState = TableState::kRow;
-            }
-            if (TableState::kRow == fTableState) {
-                fTableState = TableState::kColumn;
-            }
             TextParser paramParser(def->fFileName, def->fStart, def->fContentStart,
                     def->fLineCount);
             paramParser.skipWhiteSpace();
@@ -254,6 +240,8 @@
        } break;
         case MarkType::kPlatform:
             break;
+        case MarkType::kPopulate:
+            break;
         case MarkType::kPrivate:
             break;
         case MarkType::kReturn:
@@ -262,6 +250,8 @@
             break;
         case MarkType::kSeeAlso:
             break;
+        case MarkType::kSet:
+            break;
         case MarkType::kStdOut: {
             fInStdOut = true;
             TextParser code(def);
@@ -336,8 +326,6 @@
         case MarkType::kConst:
             fInConst = false;
         case MarkType::kParam:
-            SkASSERT(TableState::kColumn == fTableState);
-            fTableState = TableState::kRow;
             break;
         case MarkType::kReturn:
         case MarkType::kSeeAlso:
@@ -390,6 +378,7 @@
     const char* wordStart = nullptr;
     const char* wordEnd = nullptr;
     const char* possibleEnd = nullptr;
+    fLocalLine = 0;
     do {
         if (wordStart && wordEnd) {
             if (!allLower || (!inQuotes && '\"' != lastCh && !inParens
@@ -457,6 +446,9 @@
                 allLower = false;
             case '-':  // note that dash doesn't clear allLower
                 break;
+            case '\n':
+                ++fLocalLine;
+                // fall through
             default:
                 wordEnd = chPtr;
                 break;
@@ -492,7 +484,8 @@
                 continue;
             }
             if (iter.second.fCount == 1) {
-                SkDebugf("%s(%d): %s\n", iter.second.fFile.c_str(), iter.second.fLine,
+                string fullName = this->ReportFilename(iter.second.fFile);
+                SkDebugf("%s(%d): %s\n", fullName.c_str(), iter.second.fLine,
                         iter.first.c_str());
             }
         }
@@ -562,7 +555,8 @@
             break;
         }
         if (check.compare(mispelled) == 0) {
-            SkDebugf("%s(%d): %s\n", iter.second.fFile.c_str(), iter.second.fLine,
+            string fullName = this->ReportFilename(iter.second.fFile);
+            SkDebugf("%s(%d): %s\n", fullName.c_str(), iter.second.fLine,
                     iter.first.c_str());
             if (report.count() == ++index) {
                 break;
@@ -651,9 +645,12 @@
     if (mappy.end() != iter) {
         iter->second.fCount += 1;
     } else {
+        if ("offscreen" == str) {
+            SkDebugf("");
+        }
         CheckEntry* entry = &mappy[str];
         entry->fFile = fFileName;
-        entry->fLine = fLineCount;
+        entry->fLine = fLineCount + fLocalLine;
         entry->fCount = 1;
     }
 }