wip pixmap docs

wip pixmap docs

Docs-Preview: https://skia.org/?cl=42522
Bug: skia: 6898
Change-Id: I85947bc36ea057ed008b87d7bef2efa82d7c89ad
Reviewed-on: https://skia-review.googlesource.com/42522
Reviewed-by: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index ac8f04d..1df8d42 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -938,6 +938,7 @@
                     definition->fFiddle = normalized_name(name);
                 }
                 definition->fMarkType = markType;
+                definition->fAnonymous = fAnonymous;
                 this->setAsParent(definition);
             }
             } break;
@@ -1078,9 +1079,6 @@
                 fMarkup.emplace_front(markType, defStart, fLineCount, fParent);
                 definition = &fMarkup.front();
                 definition->fContentStart = fChar;
-                if (MarkType::kFormula == markType && MarkType::kRow == definition->fParent->fMarkType) {
-                    SkDebugf("");
-                }
                 definition->fName = typeNameBuilder[0];
                 definition->fFiddle = fParent->fFiddle;
                 char suffix = '\0';
@@ -1383,6 +1381,7 @@
     }
     fprintf(fiddleOut, "\n}\n");
     fclose(fiddleOut);
+    SkDebugf("wrote %s\n", fiddleJsonFileName);
     return true;
 }
 
@@ -1525,10 +1524,6 @@
                         }
                     }
                 } else if (TableState::kNone == fTableState) {
-                    bool parentIsList = MarkType::kList == fParent->fMarkType;
-                    if (parentIsList && fLineCount > 1230) {
-                        SkDebugf("");
-                    }
                     // fixme? no nested tables for now
                     fColStart = fChar - 1;
                     fMarkup.emplace_front(MarkType::kRow, fColStart, fLineCount, fParent);
@@ -1627,6 +1622,7 @@
     } while (!this->eof());
     fprintf(out, "%.*s", (int) (fEnd - start), start);
     fclose(out);
+    SkDebugf("wrote %s\n", filename.c_str());
     return true;
 }
 
@@ -2143,15 +2139,16 @@
 // pass one: parse text, collect definitions
 // pass two: lookup references
 
-DEFINE_string2(bmh, b, "", "A path to a *.bmh file or a directory.");
+DEFINE_string2(bmh, b, "", "Path to a *.bmh file or a directory.");
 DEFINE_string2(examples, e, "", "File of fiddlecli input, usually fiddle.json (For now, disables -r -f -s)");
 DEFINE_string2(fiddle, f, "", "File of fiddlecli output, usually fiddleout.json.");
-DEFINE_string2(include, i, "", "A path to a *.h file or a directory.");
+DEFINE_string2(include, i, "", "Path to a *.h file or a directory.");
 DEFINE_bool2(hack, k, false, "Do a find/replace hack to update all *.bmh files. (Requires -b)");
+DEFINE_bool2(stdout, o, false, "Write file out to standard out.");
 DEFINE_bool2(populate, p, false, "Populate include from bmh. (Requires -b -i)");
 DEFINE_string2(ref, r, "", "Resolve refs and write bmh_*.md files to path. (Requires -b)");
-DEFINE_string2(spellcheck, s, "", "Spell-check [once, all, mispellings]. (Requires -b)");
-DEFINE_bool2(tokens, t, false, "Output include tokens. (Requires -i)");
+DEFINE_string2(spellcheck, s, "", "Spell-check [once, all, mispelling]. (Requires -b)");
+DEFINE_string2(tokens, t, "", "Directory to write bmh from include. (Requires -i)");
 DEFINE_bool2(crosscheck, x, false, "Check bmh against includes. (Requires -b -i)");
 
 static int count_children(const Definition& def, MarkType markType) {
@@ -2220,7 +2217,6 @@
             SkDebugf("hack failed\n");
             return -1;
         }
-        SkDebugf("hack success\n");
         return 0;
     }
     if ((FLAGS_include.isEmpty() || FLAGS_bmh.isEmpty()) && FLAGS_populate) {
@@ -2238,7 +2234,7 @@
         SkCommandLineFlags::PrintUsage();
         return 1;
     }
-    if (FLAGS_include.isEmpty() && FLAGS_tokens) {
+    if (FLAGS_include.isEmpty() && !FLAGS_tokens.isEmpty()) {
         SkDebugf("-t requires -i\n");
         SkCommandLineFlags::PrintUsage();
         return 1;
@@ -2255,14 +2251,16 @@
     }
     bool done = false;
     if (!FLAGS_include.isEmpty()) {
-        if (FLAGS_tokens || FLAGS_crosscheck) {
+        if (!FLAGS_tokens.isEmpty() || FLAGS_crosscheck) {
             IncludeParser includeParser;
             includeParser.validate();
             if (!includeParser.parseFile(FLAGS_include[0], ".h")) {
                 return -1;
             }
-            if (FLAGS_tokens) {
-                includeParser.dumpTokens();
+            if (!FLAGS_tokens.isEmpty()) {
+                if (includeParser.dumpTokens(FLAGS_tokens[0])) {
+                    bmhParser.fWroteOut = true;
+                }
                 done = true;
             } else if (FLAGS_crosscheck) {
                 if (!includeParser.crossCheck(bmhParser)) {
@@ -2276,9 +2274,11 @@
             if (!includeWriter.parseFile(FLAGS_include[0], ".h")) {
                 return -1;
             }
+            includeWriter.fDebugOut = FLAGS_stdout;
             if (!includeWriter.populate(bmhParser)) {
                 return -1;
             }
+            bmhParser.fWroteOut = true;
             done = true;
         }
     }
@@ -2290,7 +2290,9 @@
     }
     if (!done && !FLAGS_ref.isEmpty() && FLAGS_examples.isEmpty()) {
         MdOut mdOut(bmhParser);
-        mdOut.buildReferences(FLAGS_bmh[0], FLAGS_ref[0]);
+        if (mdOut.buildReferences(FLAGS_bmh[0], FLAGS_ref[0])) {
+            bmhParser.fWroteOut = true;
+        }
     }
     if (!done && !FLAGS_spellcheck.isEmpty() && FLAGS_examples.isEmpty()) {
         bmhParser.spellCheck(FLAGS_bmh[0], FLAGS_spellcheck);
@@ -2307,18 +2309,21 @@
         if (!bmhParser.dumpExamples(FLAGS_examples[0])) {
             return -1;
         }
+        return 0;
     }
-    for (const auto& topic : bmhParser.fTopicMap) {
-        if (topic.second->fParent) {
-            continue;
+    if (!bmhParser.fWroteOut) {
+        for (const auto& topic : bmhParser.fTopicMap) {
+            if (topic.second->fParent) {
+                continue;
+            }
+            examples += count_children(*topic.second, MarkType::kExample);
+            methods += count_children(*topic.second, MarkType::kMethod);
+            topics += count_children(*topic.second, MarkType::kSubtopic);
+            topics += count_children(*topic.second, MarkType::kTopic);
         }
-        examples += count_children(*topic.second, MarkType::kExample);
-        methods += count_children(*topic.second, MarkType::kMethod);
-        topics += count_children(*topic.second, MarkType::kSubtopic);
-        topics += count_children(*topic.second, MarkType::kTopic);
+        SkDebugf("topics=%d classes=%d methods=%d examples=%d\n", 
+                bmhParser.fTopicMap.size(), bmhParser.fClassMap.size(),
+                methods, examples);
     }
-    SkDebugf("topics=%d classes=%d methods=%d examples=%d\n", 
-            bmhParser.fTopicMap.size(), bmhParser.fClassMap.size(),
-            methods, examples);
     return 0;
 }
diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h
index 503db20..1d95f13 100644
--- a/tools/bookmaker/bookmaker.h
+++ b/tools/bookmaker/bookmaker.h
@@ -8,8 +8,6 @@
 #ifndef bookmaker_DEFINED
 #define bookmaker_DEFINED
 
-#define STDOUT_TO_IDE_OUT 0
-
 #include "SkCommandLineFlags.h"
 #include "SkData.h"
 
@@ -71,7 +69,10 @@
     kStruct,
     kTemplate,
     kTypedef,
+    kUint16_t,
     kUint32_t,
+    kUint64_t,
+    kUint8_t,
     kUnion,
     kUnsigned,
     kVoid,
@@ -161,6 +162,24 @@
     kColon,     // for foo() : bar(1), baz(2) {}
 };
 
+enum class KeyProperty {
+    kNone,
+    kClassSection,
+    kFunction,
+    kModifier,
+    kNumber,
+    kObject,
+    kPreprocessor,
+};
+
+struct IncludeKey {
+    const char* fName;
+    KeyWord fKeyWord;
+    KeyProperty fProperty;
+};
+
+extern const IncludeKey kKeyWords[];
+
 static inline bool has_nonwhitespace(const string& s) {
     bool nonwhite = false;
     for (const char& c : s) {
@@ -449,7 +468,9 @@
     bool skipName(const char* word) {
         size_t len = strlen(word);
         if (len <= (size_t) (fEnd - fChar) && !strncmp(word, fChar, len)) {
-            fChar += len;
+            for (size_t i = 0; i < len; ++i) {
+                this->next();
+            }
         }
         return this->eof() || ' ' >= fChar[0];
     }
@@ -890,6 +911,7 @@
     bool fPrivate = false;
     bool fShort = false;
     bool fMemberStart = false;
+    bool fAnonymous = false;
     mutable bool fVisited = false;
 };
 
@@ -959,6 +981,7 @@
 
     ParserCommon() : TextParser()
         , fParent(nullptr)
+        , fDebugOut(false)
     {
     }
 
@@ -972,9 +995,9 @@
 
     void indentToColumn(int column) {
         SkASSERT(column >= fColumn);
-#if STDOUT_TO_IDE_OUT
-        SkDebugf("%*s", column - fColumn, "");
-#endif
+        if (fDebugOut) {
+            SkDebugf("%*s", column - fColumn, "");
+        }
         fprintf(fOut, "%*s", column - fColumn, "");
         fColumn = column;
         fSpaces += column - fColumn;
@@ -1068,10 +1091,13 @@
             fPendingSpace = false;
         }
         writePending();
-#if STDOUT_TO_IDE_OUT
-        string check(data, size);
-        SkDebugf("%s", check.c_str());
-#endif
+        if (fDebugOut) {
+            if (!strncmp("SK_SUPPORT", data, 10)) {
+                SkDebugf("");
+            }
+            string check(data, size);
+            SkDebugf("%s", check.c_str());
+        }
         fprintf(fOut, "%.*s", size, data);
         int added = 0;
         while (size > 0 && '\n' != data[--size]) {
@@ -1109,9 +1135,6 @@
     }
 
     void writeString(const char* str) {
-        if (!strcmp("utf-8", str)) {
-            SkDebugf("");
-        }
         SkASSERT(strlen(str) > 0);
         SkASSERT(' ' < str[0]);
         SkASSERT(' ' < str[strlen(str) - 1]);
@@ -1119,9 +1142,12 @@
             fPendingSpace = false;
         }
         writePending();
-#if STDOUT_TO_IDE_OUT
-        SkDebugf("%s", str);
-#endif
+        if (fDebugOut) {
+            if (!strncmp("SK_SUPPORT", str, 10)) {
+                SkDebugf("");
+            }
+            SkDebugf("%s", str);
+        }
         SkASSERT(!strchr(str, '\n'));
         fprintf(fOut, "%s", str);
         fColumn += strlen(str);
@@ -1134,9 +1160,9 @@
         fPendingLF = SkTMin(fPendingLF, fMaxLF);
         bool wroteLF = false;
         while (fLinefeeds < fPendingLF) {
-#if STDOUT_TO_IDE_OUT
-            SkDebugf("\n");
-#endif
+            if (fDebugOut) {
+                SkDebugf("\n");
+            }
             fprintf(fOut, "\n");
             ++fLinefeeds;
             wroteLF = true;
@@ -1145,17 +1171,17 @@
         if (wroteLF) {
             SkASSERT(0 == fColumn);
             SkASSERT(fIndent >= fSpaces);
-    #if STDOUT_TO_IDE_OUT
-            SkDebugf("%*s", fIndent - fSpaces, "");
-    #endif
+            if (fDebugOut) {
+                SkDebugf("%*s", fIndent - fSpaces, "");
+            }
             fprintf(fOut, "%*s", fIndent - fSpaces, "");
             fColumn = fIndent;
             fSpaces = fIndent;
         }
         if (fPendingSpace) {
-    #if STDOUT_TO_IDE_OUT
-            SkDebugf(" ");
-    #endif
+            if (fDebugOut) {
+                SkDebugf(" ");
+            }
             fprintf(fOut, " ");
             ++fColumn;
             fPendingSpace = false;
@@ -1173,6 +1199,7 @@
     int fColumn;        // current column; number of chars past last linefeed
     int fIndent;        // desired indention
     bool fPendingSpace; // a space should preceed the next string or block
+    bool fDebugOut;     // set true to write to std out
 private:
     typedef TextParser INHERITED;
 };
@@ -1231,7 +1258,7 @@
 , { "Alias",       nullptr,      MarkType::kAlias,        R_N, E_N, 0 }
 , { "Bug",         nullptr,      MarkType::kBug,          R_N, E_N, 0 }
 , { "Class",       &fClassMap,   MarkType::kClass,        R_Y, E_O, M_CSST | M(Root) }
-, { "Code",        nullptr,      MarkType::kCode,         R_Y, E_N, M_CSST | M_E }      
+, { "Code",        nullptr,      MarkType::kCode,         R_O, E_N, M_CSST | M_E }      
 , { "",            nullptr,      MarkType::kColumn,       R_Y, E_N, M(Row) }
 , { "",            nullptr,      MarkType::kComment,      R_N, E_N, 0 }
 , { "Const",       &fConstMap,   MarkType::kConst,        R_Y, E_N, M_E | M_ST  }
@@ -1396,7 +1423,7 @@
     bool fInComment;
     bool fInString;
     bool fCheckMethods;
-
+    bool fWroteOut = false;
 private:
     typedef ParserCommon INHERITED;
 };
@@ -1489,7 +1516,7 @@
     IClassDefinition* defineClass(const Definition& includeDef, const string& className);
     void dumpClassTokens(IClassDefinition& classDef);
     void dumpComment(Definition* token);
-    void dumpTokens();
+    bool dumpTokens(const string& directory);
     bool findComments(const Definition& includeDef, Definition* markupDef);
 
     Definition* findIncludeObject(const Definition& includeDef, MarkType markType,
@@ -1651,6 +1678,11 @@
         kMixed,
     };
 
+    enum class Phrase {
+        kNo,
+        kYes,
+    };
+
     enum class PunctuationState {
         kStart,
         kDelimiter,
@@ -1721,11 +1753,12 @@
         fAttrDeprecated = nullptr;
         fAnonymousEnumCount = 1;
         fInStruct = false;
+        fWroteMethod = false;
     }
 
     string resolveMethod(const char* start, const char* end, bool first);
     string resolveRef(const char* start, const char* end, bool first, RefType* refType);
-    Wrote rewriteBlock(int size, const char* data);
+    Wrote rewriteBlock(int size, const char* data, Phrase phrase);
     Definition* structMemberOut(const Definition* memberStart, const Definition& child);
     void structOut(const Definition* root, const Definition& child,
             const char* commentStart, const char* commentEnd);
@@ -1748,6 +1781,7 @@
     int fStructValueTab;
     int fStructCommentTab;
     bool fInStruct;
+    bool fWroteMethod;
 
     typedef IncludeParser INHERITED;
 };
@@ -1822,6 +1856,7 @@
     bool buildRefFromFile(const char* fileName, const char* outDir);
     bool checkParamReturnBody(const Definition* def) const;
     void childrenOut(const Definition* def, const char* contentStart);
+    const Definition* findParamType();
     const Definition* isDefined(const TextParser& parser, const string& ref, bool report) const;
     string linkName(const Definition* ) const;
     string linkRef(const string& leadingSpaces, const Definition*, const string& ref) const;
@@ -1837,6 +1872,7 @@
         fEnumClass = nullptr;
         fMethod = nullptr;
         fRoot = nullptr;
+        fLastParam = nullptr;
         fTableState = TableState::kNone;
         fHasFiddle = false;
         fInDescription = false;
@@ -1857,6 +1893,7 @@
     const Definition* fEnumClass;
     Definition* fMethod;
     RootDefinition* fRoot;
+    const Definition* fLastParam;
     TableState fTableState;
     bool fHasFiddle;
     bool fInDescription;   // FIXME: for now, ignore unfound camelCase in description since it may
diff --git a/tools/bookmaker/fiddleParser.cpp b/tools/bookmaker/fiddleParser.cpp
index d5cfcf4..3361543 100644
--- a/tools/bookmaker/fiddleParser.cpp
+++ b/tools/bookmaker/fiddleParser.cpp
@@ -55,7 +55,6 @@
         if (']' != this->peek()) {
             // report compiler errors
             int brackets = 1;
-            const char* errorStart = fChar;
             do {
                 if ('[' == this->peek()) {
                     ++brackets;
@@ -63,8 +62,7 @@
                     --brackets;
                 }
             } while (!this->eof() && this->next() && brackets > 0);
-            SkDebugf("fiddle compile error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
-                    errorStart);
+            this->reportError("fiddle compile error");
         }
         if (!this->skipExact("],\n")) {
             return false;
@@ -73,12 +71,10 @@
             return false;
         }
         if ('"' != this->peek()) {
-            const char* errorStart = fChar;
             if (!this->skipToEndBracket('"')) {
                 return false;
             }
-            SkDebugf("fiddle runtime error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
-                    errorStart);
+            this->reportError("fiddle runtime error");
         }
         if (!this->skipExact("\",\n")) {
             return false;
@@ -92,7 +88,7 @@
         }
         Definition* example = this->findExample(name);
         if (!example) {
-            SkDebugf("missing example %s\n", name.c_str());
+            this->reportError("missing example");
         }
         string hash(hashStart, fChar - hashStart);
         if (example) {
@@ -141,21 +137,21 @@
                         SkASSERT(fiddleLen > 0);
                         if (bmhLen != fiddleLen) {
                             if (!foundVolatile) {
-                                SkDebugf("mismatched stdout len in %s\n", name.c_str());
+                                bmh.reportError("mismatched stdout len\n");
                             }
                         } else  if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
                             if (!foundVolatile) {
-                                SkDebugf("mismatched stdout text in %s\n", name.c_str());
+                                bmh.reportError("mismatched stdout text\n");
                             }
                         }
                         bmh.skipToLineStart();
                         fiddle.skipToLineStart();
                     } while (!bmh.eof() && !fiddle.eof());
                     if (!foundStdOut) {
-                        SkDebugf("bmh %s missing stdout\n", name.c_str());
+                        bmh.reportError("bmh %s missing stdout\n");
                     } else if (!bmh.eof() || !fiddle.eof()) {
                         if (!foundVolatile) {
-                            SkDebugf("%s mismatched stdout eof\n", name.c_str());
+                            bmh.reportError("%s mismatched stdout eof\n");
                         }
                     }
                 }
diff --git a/tools/bookmaker/includeParser.cpp b/tools/bookmaker/includeParser.cpp
index cc7627a..1000a03 100644
--- a/tools/bookmaker/includeParser.cpp
+++ b/tools/bookmaker/includeParser.cpp
@@ -7,22 +7,6 @@
 
 #include "bookmaker.h"
 
-enum class KeyProperty {
-    kNone,
-    kClassSection,
-    kFunction,
-    kModifier,
-    kNumber,
-    kObject,
-    kPreprocessor,
-};
-
-struct IncludeKey {
-    const char* fName;
-    KeyWord fKeyWord;
-    KeyProperty fProperty;
-};
-
 const IncludeKey kKeyWords[] = {
     { "",           KeyWord::kNone,         KeyProperty::kNone           },
     { "SK_API",     KeyWord::kSK_API,       KeyProperty::kModifier       },
@@ -55,7 +39,10 @@
     { "struct",     KeyWord::kStruct,       KeyProperty::kObject         },
     { "template",   KeyWord::kTemplate,     KeyProperty::kObject         },
     { "typedef",    KeyWord::kTypedef,      KeyProperty::kObject         },
+    { "uint16_t",   KeyWord::kUint16_t,     KeyProperty::kNumber         },
     { "uint32_t",   KeyWord::kUint32_t,     KeyProperty::kNumber         },
+    { "uint64_t",   KeyWord::kUint64_t,     KeyProperty::kNumber         },
+    { "uint8_t",    KeyWord::kUint8_t,      KeyProperty::kNumber         },
     { "union",      KeyWord::kUnion,        KeyProperty::kObject         },
     { "unsigned",   KeyWord::kUnsigned,     KeyProperty::kNumber         },
     { "void",       KeyWord::kVoid,         KeyProperty::kNumber         },
@@ -417,6 +404,8 @@
     if (!root->dumpUnVisited()) {
         SkDebugf("some struct elements not found; struct finding in includeParser is missing\n");
     }
+    SkDebugf("cross-checked %s\n", className.c_str());
+    bmhParser.fWroteOut = true;
     return true;
 }
 
@@ -683,13 +672,17 @@
 }
 
     // dump equivalent markup 
-void IncludeParser::dumpTokens()  {
+bool IncludeParser::dumpTokens(const string& dir) {
     string skClassName = this->className();
-    string fileName = skClassName + ".bmh";
+    string fileName = dir;
+    if (dir.length() && '/' != dir[dir.length() - 1]) {
+        fileName += '/';
+    }
+    fileName += skClassName + "_Reference.bmh";
     fOut = fopen(fileName.c_str(), "wb");
     if (!fOut) {
         SkDebugf("could not open output file %s\n", fileName.c_str());
-        return;
+        return false;
     }
     string prefixName = skClassName.substr(0, 2);
     string topicName = skClassName.length() > 2 && isupper(skClassName[2]) &&
@@ -811,6 +804,8 @@
     fprintf(fOut, "#Topic %s ##"                                                             "\n",
             topicName.c_str());
     fclose(fOut);
+    SkDebugf("wrote %s\n", fileName.c_str());
+    return true;
 }
 
 bool IncludeParser::findComments(const Definition& includeDef, Definition* markupDef) {
@@ -960,7 +955,8 @@
             if (!parser.skipWord(kKeyWords[(int) markupDef->fKeyWord].fName)) {
                 return reportError<bool>("missing object type");
             }
-            if (!parser.skipWord(markupDef->fName.c_str())) {
+            if (!parser.skipWord(markupDef->fName.c_str()) &&
+                    KeyWord::kEnum != markupDef->fKeyWord) {
                 return reportError<bool>("missing object name");
             }
 
@@ -1232,6 +1228,9 @@
             break;
         }
     }
+    while (end > start && ' ' >= end[-1]) {
+        --end;
+    }
     markupDef->fTokens.emplace_back(MarkType::kMethod, start, end, tokenIter->fLineCount,
             markupDef);
     Definition* markupChild = &markupDef->fTokens.back();
@@ -1404,14 +1403,14 @@
     char test = *fChar;
     if ('\\' == fPrev) {
         if ('\n' == test) {
-            ++fLineCount;
+//            ++fLineCount;
             fLine = fChar + 1;
         }
         goto done;
     }
     switch (test) {
         case '\n':
-            ++fLineCount;
+//            ++fLineCount;
             fLine = fChar + 1;
             if (fInChar) {
                 return reportError<bool>("malformed char");
@@ -1777,7 +1776,7 @@
     }
 done:
     fPrev = test;
-    ++fChar;
+    this->next();
     return true;
 }
 
diff --git a/tools/bookmaker/includeWriter.cpp b/tools/bookmaker/includeWriter.cpp
index 78b0364..90f0d6c 100644
--- a/tools/bookmaker/includeWriter.cpp
+++ b/tools/bookmaker/includeWriter.cpp
@@ -79,12 +79,12 @@
             this->lfcr();
             wroteHeader = true;
         }
-        this->rewriteBlock((int) (commentEnd - commentStart), commentStart);
+        this->rewriteBlock((int) (commentEnd - commentStart), commentStart, Phrase::kNo);
         if (MarkType::kAnchor == test->fMarkType) {
             commentStart = test->fContentStart;
             commentEnd = test->fChildren[0]->fStart;
             this->writeSpace();
-            this->rewriteBlock((int) (commentEnd - commentStart), commentStart);
+            this->rewriteBlock((int) (commentEnd - commentStart), commentStart, Phrase::kNo);
             this->writeSpace();
         }
         commentStart = test->fTerminator;
@@ -207,7 +207,7 @@
                 this->indentToColumn(fEnumItemCommentTab);
                 this->writeString("//!<");
                 this->writeSpace();
-                this->rewriteBlock(commentLen, commentStart);
+                this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
             }
             if (onePast) {
                 fIndent -= 4;
@@ -274,7 +274,8 @@
         if (!currentEnumItem->fShort) {
             this->writeCommentHeader();
             fIndent += 4;
-            bool wroteLineFeed = Wrote::kLF == this->rewriteBlock(commentLen, commentStart);
+            bool wroteLineFeed = Wrote::kLF ==
+                    this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
             fIndent -= 4;
             if (wroteLineFeed || fColumn > 100 - 3 /* space * / */ ) {
                 this->lfcr();
@@ -405,6 +406,9 @@
 
 // walk children and output complete method doxygen description
 void IncludeWriter::methodOut(const Definition* method, const Definition& child) {
+    if ("SkPath::getGenerationID" == method->fName) {
+        SkDebugf("");
+    }
     fBmhMethod = method;
     fMethodDef = &child;
     fContinuation = nullptr;
@@ -427,14 +431,14 @@
                 commentLen = (int) (methodProp->fStart - commentStart);
                 if (commentLen > 0) {
                     SkASSERT(commentLen < 1000);
-                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart)) {
+                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) {
                         this->lfcr();
                     }
                 }
                 commentStart = methodProp->fContentStart;
                 commentLen = (int) (methodProp->fContentEnd - commentStart);
                 if (commentLen > 0) {
-                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart)) {
+                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) {
                         this->lfcr();
                     }
                 }
@@ -447,7 +451,7 @@
                 commentStart = methodProp->fContentStart;
                 commentLen = (int) (methodProp->fContentEnd - commentStart);
                 if (commentLen > 0) {
-                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart)) {
+                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) {
                         this->lfcr();
                     }
                 }
@@ -458,7 +462,7 @@
                 commentLen = (int) (methodProp->fStart - commentStart);
                 if (commentLen > 0) {
                     SkASSERT(commentLen < 1000);
-                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart)) {
+                    if (Wrote::kNone != this->rewriteBlock(commentLen, commentStart, Phrase::kNo)) {
                         this->lfcr();
                     }
                 }
@@ -474,7 +478,7 @@
         }
     }
     SkASSERT(commentLen > 0 && commentLen < 1500);
-    this->rewriteBlock(commentLen, commentStart);
+    this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
     // compute indention column
     size_t column = 0;
     bool hasParmReturn = false;
@@ -513,7 +517,7 @@
             // FIXME : detect this earlier; assert if #Return is empty
             SkASSERT(partLen > 0 && partLen < 200);
             fIndent = column;
-            this->rewriteBlock(partLen, partStart);
+            this->rewriteBlock(partLen, partStart, Phrase::kYes);
             fIndent = saveIndent;
             this->lfcr();
         }
@@ -525,6 +529,7 @@
     this->writeCommentTrailer();
     fBmhMethod = nullptr;
     fMethodDef = nullptr;
+    fWroteMethod = true;
 }
 
 void IncludeWriter::structOut(const Definition* root, const Definition& child,
@@ -537,15 +542,18 @@
     this->writeString(child.fName.c_str());
     fIndent += 4;
     this->lfcr();
-    this->rewriteBlock((int) (commentEnd - commentStart), commentStart);
+    this->rewriteBlock((int) (commentEnd - commentStart), commentStart, Phrase::kNo);
     fIndent -= 4;
     this->lfcr();
     this->writeCommentTrailer();
 }
 
 Definition* IncludeWriter::structMemberOut(const Definition* memberStart, const Definition& child) {
-    const char* blockStart = fDeferComment ? fLastComment->fContentEnd : fStart;
-    this->writeBlockTrim((int) (memberStart->fStart - blockStart), blockStart);
+    const char* blockStart = !fWroteMethod && fDeferComment ? fLastComment->fContentEnd : fStart;
+    const char* blockEnd = fWroteMethod && fDeferComment ? fDeferComment->fStart - 1 :
+            memberStart->fStart;
+    this->writeBlockTrim((int) (blockEnd - blockStart), blockStart);
+    fWroteMethod = false;
     const char* commentStart = nullptr;
     ptrdiff_t commentLen = 0;
     string name(child.fContentStart, (int) (child.fContentEnd - child.fContentStart));
@@ -567,7 +575,7 @@
         fIndent += 4;
         for (auto child : commentBlock->fChildren) {
             commentLen = child->fStart - commentStart;
-            wroteLineFeed |= Wrote::kLF == this->rewriteBlock(commentLen, commentStart);
+            wroteLineFeed |= Wrote::kLF == this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
             if (MarkType::kFormula == child->fMarkType) {
                 this->writeSpace();
                 this->writeBlock((int) (child->fContentEnd - child->fContentStart),
@@ -576,7 +584,7 @@
             commentStart = child->fTerminator;
         }
         commentLen = commentBlock->fContentEnd - commentStart;
-        wroteLineFeed |= Wrote::kLF == this->rewriteBlock(commentLen, commentStart);
+        wroteLineFeed |= Wrote::kLF == this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
         fIndent -= 4;
         if (wroteLineFeed || fColumn > 100 - 3 /* space * / */ ) {
             this->lfcr();
@@ -610,7 +618,7 @@
         this->indentToColumn(fStructCommentTab);
         this->writeString("//!<");
         this->writeSpace();
-        this->rewriteBlock(commentLen, commentStart);
+        this->rewriteBlock(commentLen, commentStart, Phrase::kNo);
         this->lfcr();
     }
     return valueEnd;
@@ -652,7 +660,10 @@
                 case KeyWord::kConstExpr:
                 case KeyWord::kStatic:
                 case KeyWord::kInt:
+                case KeyWord::kUint8_t:
+                case KeyWord::kUint16_t:
                 case KeyWord::kUint32_t:
+                case KeyWord::kUint64_t:
                 case KeyWord::kSize_t:
                 case KeyWord::kFloat:
                 case KeyWord::kBool:
@@ -768,10 +779,14 @@
         }
         if (fContinuation) {
             if (Definition::Type::kKeyWord == child.fType) {
-                if (KeyWord::kFriend == child.fKeyWord || KeyWord::kBool == child.fKeyWord ||
+                if (KeyWord::kFriend == child.fKeyWord ||
                         KeyWord::kSK_API == child.fKeyWord) {
                     continue;
                 }
+                const IncludeKey& includeKey = kKeyWords[(int) child.fKeyWord];
+                if (KeyProperty::kNumber == includeKey.fProperty) {
+                    continue;
+                }
             }
             if (Definition::Type::kBracket == child.fType && Bracket::kParen == child.fBracket) {
                 if (!clonedMethod) {
@@ -832,6 +847,11 @@
                 this->methodOut(method, child);
                 continue;
             }
+            if (Definition::Type::kPunctuation == child.fType &&
+                    Punctuation::kAsterisk == child.fPunctuation &&
+                    clonedMethod) {
+                continue;
+            }
             if (inConstructor) {
                 continue;
             }
@@ -983,7 +1003,10 @@
                 case KeyWord::kConstExpr:
                 case KeyWord::kStatic:
                 case KeyWord::kInt:
+                case KeyWord::kUint8_t:
+                case KeyWord::kUint16_t:
                 case KeyWord::kUint32_t:
+                case KeyWord::kUint64_t:
                 case KeyWord::kUnsigned:
                 case KeyWord::kSize_t:
                 case KeyWord::kFloat:
@@ -1024,6 +1047,8 @@
                 fIndent -= 4;
                 fContinuation = nullptr;
                 fDeferComment = nullptr;
+            } else if (KeyWord::kUint8_t == child.fKeyWord) {
+                continue;
             } else {
                 if (fInEnum && KeyWord::kClass == child.fChildren[0]->fKeyWord) {
                     if (!this->populate(child.fChildren[0], &pair, root)) {
@@ -1039,6 +1064,7 @@
             if (KeyWord::kEnum == child.fParent->fKeyWord || 
                     (KeyWord::kClass == child.fParent->fKeyWord && child.fParent->fParent &&
                     KeyWord::kEnum == child.fParent->fParent->fKeyWord)) {
+                SkASSERT(Bracket::kBrace == child.fBracket);
                 this->enumMembersOut(root, child);
                 this->writeString("};");
                 this->lf(2);
@@ -1098,6 +1124,9 @@
     bool allPassed = true;
     for (auto& includeMapper : fIncludeMap) {
         size_t lastSlash = includeMapper.first.rfind('/');
+        if (string::npos == lastSlash) {
+            lastSlash = includeMapper.first.rfind('\\');
+        }
         if (string::npos == lastSlash || lastSlash >= includeMapper.first.length() - 1) {
             return this->reportError<bool>("malformed include name");
         }
@@ -1126,6 +1155,7 @@
         this->lfcr();
         this->writePending();
         fclose(fOut);
+        SkDebugf("wrote %s\n", fileName.c_str());
     }
     return allPassed;
 }
@@ -1226,17 +1256,21 @@
                         (int) (child->fContentEnd - child->fContentStart));
                 break;
             }
-            if (MarkType::kClass == child->fMarkType ||
-                    MarkType::kStruct == child->fMarkType ||
-                    MarkType::kEnum == child->fMarkType ||
-                    MarkType::kEnumClass == child->fMarkType) {
-                substitute = child->fName;
-                if (MarkType::kEnum == child->fMarkType && fInEnum) {
-                    size_t parentClassEnd = substitute.find("::");
-                    SkASSERT(string::npos != parentClassEnd);
-                    substitute = substitute.substr(parentClassEnd + 2);
+        }
+        if (!substitute.length()) {
+            for (auto child : rootDef->fChildren) {
+                if (MarkType::kClass == child->fMarkType ||
+                        MarkType::kStruct == child->fMarkType ||
+                        (MarkType::kEnum == child->fMarkType && !child->fAnonymous) ||
+                        MarkType::kEnumClass == child->fMarkType) {
+                    substitute = child->fName;
+                    if (MarkType::kEnum == child->fMarkType && fInEnum) {
+                        size_t parentClassEnd = substitute.find("::");
+                        SkASSERT(string::npos != parentClassEnd);
+                        substitute = substitute.substr(parentClassEnd + 2);
+                    }
+                    break;
                 }
-                break;
             }
         }
         if (!substitute.length()) {
@@ -1244,7 +1278,7 @@
             if (parent) {
                 if (MarkType::kClass == parent->fMarkType ||
                         MarkType::kStruct == parent->fMarkType ||
-                        MarkType::kEnum == parent->fMarkType ||
+                        (MarkType::kEnum == parent->fMarkType && !parent->fAnonymous) ||
                         MarkType::kEnumClass == parent->fMarkType) {
                     if (parent->fParent != fRootTopic) {
                         substitute = parent->fName;
@@ -1324,7 +1358,7 @@
 }
 
 /* returns true if rewriteBlock wrote linefeeds */
-IncludeWriter::Wrote IncludeWriter::rewriteBlock(int size, const char* data) {
+IncludeWriter::Wrote IncludeWriter::rewriteBlock(int size, const char* data, Phrase phrase) {
     bool wroteLineFeeds = false;
     while (size > 0 && data[0] <= ' ') {
         --size;
@@ -1338,7 +1372,8 @@
     }
     int run = 0;
     Word word = Word::kStart;
-    PunctuationState punctuation = PunctuationState::kStart;
+    PunctuationState punctuation = Phrase::kNo == phrase ?
+            PunctuationState::kStart : PunctuationState::kSpace;
     int start = 0;
     int lastWrite = 0;
     int lineFeeds = 0;
diff --git a/tools/bookmaker/mdOut.cpp b/tools/bookmaker/mdOut.cpp
index 0a53fc4..b0cec66 100644
--- a/tools/bookmaker/mdOut.cpp
+++ b/tools/bookmaker/mdOut.cpp
@@ -22,7 +22,9 @@
     bool lineStart = true;
     string ref;
     string leadingSpaces;
+    int distFromParam = 99;
     do {
+        ++distFromParam;
         const char* base = t.fChar;
         t.skipWhiteSpace();
         const char* wordStart = t.fChar;
@@ -138,6 +140,8 @@
             const Definition* def;
             if (fMethod && (def = fMethod->hasParam(ref))) {
                 result += linkRef(leadingSpaces, def, ref);
+                fLastParam = def;
+                distFromParam = 0;
                 continue;
             } else if (!fInDescription && ref[0] != '0' 
                     && string::npos != ref.find_first_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
@@ -145,6 +149,23 @@
                 if (('f' != ref[0] && string::npos == ref.find("()"))
 //                        || '.' != t.backup(ref.c_str())
                         && ('k' != ref[0] && string::npos == ref.find("_Private"))) {
+                    if ('.' == wordStart[0] && distFromParam == 1) {
+                        const Definition* paramType = this->findParamType();
+                        if (paramType) {
+                            string fullName = paramType->fName + "::" + ref;
+                            bool found = false;
+                            for (auto child : paramType->fChildren) {
+                                if (fullName == child->fName) {
+                                    result += linkRef(leadingSpaces, paramType, ref);
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (found) {
+                                continue;
+                            }
+                        }
+                    }
                     if (BmhParser::Resolvable::kOut != resolvable) {
                         t.reportError("missed camelCase");
                         return result;
@@ -242,6 +263,7 @@
     filename = match + ".md";
     match += ".bmh";
     fOut = nullptr;
+    string fullName;
     for (const auto& topic : fBmhParser.fTopicMap) {
         Definition* topicDef = topic.second;
         if (topicDef->fParent) {
@@ -255,7 +277,7 @@
             continue;
         }
         if (!fOut) {
-            string fullName(outDir);
+            fullName = outDir;
             if ('/' != fullName.back()) {
                 fullName += '/';
             }
@@ -279,6 +301,7 @@
     if (fOut) {
         this->writePending();
         fclose(fOut);
+        SkDebugf("wrote %s\n", fullName.c_str());
         fOut = nullptr;
     }
     return true;
@@ -330,6 +353,31 @@
     }
 }
 
+const Definition* MdOut::findParamType() {
+    SkASSERT(fMethod);
+    TextParser parser(fMethod->fFileName, fMethod->fStart, fMethod->fContentStart,
+            fMethod->fLineCount);
+    string lastFull;
+    do {
+        parser.skipToAlpha();
+        if (parser.eof()) {
+            return nullptr;
+        }
+        const char* word = parser.fChar;
+        parser.skipFullName();
+        SkASSERT(!parser.eof());
+        string name = string(word, parser.fChar - word);
+        if (fLastParam->fName == name) {
+            const Definition* paramType = this->isDefined(parser, lastFull, false);
+            return paramType;
+        }
+        if (isupper(name[0])) {
+            lastFull = name; 
+        }
+    } while (true);
+    return nullptr;
+}
+
 const Definition* MdOut::isDefined(const TextParser& parser, const string& ref, bool report) const {
     auto rootIter = fBmhParser.fClassMap.find(ref);
     if (rootIter != fBmhParser.fClassMap.end()) {
diff --git a/tools/bookmaker/spellCheck.cpp b/tools/bookmaker/spellCheck.cpp
index 06a5d2b..7a45fb0 100644
--- a/tools/bookmaker/spellCheck.cpp
+++ b/tools/bookmaker/spellCheck.cpp
@@ -485,9 +485,11 @@
             }
         }
         SkDebugf("\n");
+        return;
     }
     if (report.contains("all")) {
         int column = 0;
+        char lastInitial = 'a';
         for (auto iter : elems) {
             if (string::npos != iter.second.fFile.find("undocumented.bmh")) {
                 continue;
@@ -509,50 +511,47 @@
             if (!allLower) {
                 continue;
             }
-            if (column + check.length() > 100) {
+            if (column + check.length() > 100 || check[0] != lastInitial) {
                 SkDebugf("\n");
                 column = 0;
             }
+            if (check[0] != lastInitial) {
+                SkDebugf("\n");
+                lastInitial = check[0];
+            }
             SkDebugf("%s ", check.c_str());
             column += check.length();
         }
         SkDebugf("\n\n");
+        return;
     }
-    if (report.contains("mispellings")) {
-        const char* mispelled[] = {
-            "decrementing",
-            "differentially",
-            "incrementing",
-            "superset",
-        };
-        const char** mispellPtr = mispelled;
-        const char** mispellEnd = &mispelled[SK_ARRAY_COUNT(mispelled)];
-        for (auto iter : elems) {
-            if (string::npos != iter.second.fFile.find("undocumented.bmh")) {
-                continue;
-            }
-            if (string::npos != iter.second.fFile.find("markup.bmh")) {
-                continue;
-            }
-            if (string::npos != iter.second.fFile.find("usingBookmaker.bmh")) {
-                continue;
-            }
-            string check = iter.first.c_str();
-            while (check.compare(*mispellPtr) > 0) {
-                SkDebugf("%s not found\n", *mispellPtr);
-                if (mispellEnd == ++mispellPtr) {
-                    break;
-                }
-            }
-            if (mispellEnd == mispellPtr) {
+    int index = 0;
+    const char* mispelled = report[0];
+    for (auto iter : elems) {
+        if (string::npos != iter.second.fFile.find("undocumented.bmh")) {
+            continue;
+        }
+        if (string::npos != iter.second.fFile.find("markup.bmh")) {
+            continue;
+        }
+        if (string::npos != iter.second.fFile.find("usingBookmaker.bmh")) {
+            continue;
+        }
+        string check = iter.first.c_str();
+        while (check.compare(mispelled) > 0) {
+            SkDebugf("%s not found\n", mispelled);
+            if (report.count() == ++index) {
                 break;
             }
-            if (check.compare(*mispellPtr) == 0) {
-                SkDebugf("%s(%d): %s\n", iter.second.fFile.c_str(), iter.second.fLine,
-                        iter.first.c_str());
-                if (mispellEnd == ++mispellPtr) {
-                    break;
-                }
+        }
+        if (report.count() == index) {
+            break;
+        }
+        if (check.compare(mispelled) == 0) {
+            SkDebugf("%s(%d): %s\n", iter.second.fFile.c_str(), iter.second.fLine,
+                    iter.first.c_str());
+            if (report.count() == ++index) {
+                break;
             }
         }
     }