Support comment groups in SkRecord.

This should fix the failing paint-command-log-nodes.html layout test.

BUG=406425
R=tomhudson@chromium.org

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/501533003
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 5dd2ba3..1101fb4 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -71,6 +71,10 @@
 DRAW(ClipRect, clipRect(r.rect, r.op, r.doAA));
 DRAW(ClipRegion, clipRegion(r.region, r.op));
 
+DRAW(BeginCommentGroup, beginCommentGroup(r.description));
+DRAW(AddComment, addComment(r.key, r.value));
+DRAW(EndCommentGroup, endCommentGroup());
+
 DRAW(DrawBitmap, drawBitmap(shallow_copy(r.bitmap), r.left, r.top, r.paint));
 DRAW(DrawBitmapMatrix, drawBitmapMatrix(shallow_copy(r.bitmap), r.matrix, r.paint));
 DRAW(DrawBitmapNine, drawBitmapNine(shallow_copy(r.bitmap), r.center, r.dst, r.paint));
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 2e14c3e..df3e1d8 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -82,6 +82,13 @@
     return dst;
 }
 
+// As above, assuming and copying a terminating \0.
+template <>
+char* SkRecorder::copy(const char* src) {
+    return this->copy(src, strlen(src)+1);
+}
+
+
 void SkRecorder::clear(SkColor color) {
     APPEND(Clear, color);
 }
@@ -276,3 +283,15 @@
     INHERITED(onClipRegion, deviceRgn, op);
     APPEND(ClipRegion, this->devBounds(), delay_copy(deviceRgn), op);
 }
+
+void SkRecorder::beginCommentGroup(const char* description) {
+    APPEND(BeginCommentGroup, this->copy(description));
+}
+
+void SkRecorder::addComment(const char* key, const char* value) {
+    APPEND(AddComment, this->copy(key), this->copy(value));
+}
+
+void SkRecorder::endCommentGroup() {
+    APPEND(EndCommentGroup);
+}
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 8b1430d..23ecdf6 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -107,6 +107,10 @@
     void onPushCull(const SkRect& cullRect) SK_OVERRIDE;
     void onPopCull() SK_OVERRIDE;
 
+    void beginCommentGroup(const char*) SK_OVERRIDE;
+    void addComment(const char*, const char*) SK_OVERRIDE;
+    void endCommentGroup() SK_OVERRIDE;
+
 private:
     template <typename T>
     T* copy(const T*);
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index f3d96d4..f216897 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -37,6 +37,9 @@
     M(ClipRect)                                                     \
     M(ClipRegion)                                                   \
     M(Clear)                                                        \
+    M(BeginCommentGroup)                                            \
+    M(AddComment)                                                   \
+    M(EndCommentGroup)                                              \
     M(DrawBitmap)                                                   \
     M(DrawBitmapMatrix)                                             \
     M(DrawBitmapNine)                                               \
@@ -211,6 +214,11 @@
 RECORD3(ClipRegion, SkIRect, devBounds, SkRegion, region, SkRegion::Op, op);
 
 RECORD1(Clear, SkColor, color);
+
+RECORD1(BeginCommentGroup, PODArray<char>, description);
+RECORD2(AddComment, PODArray<char>, key, PODArray<char>, value);
+RECORD0(EndCommentGroup);
+
 // While not strictly required, if you have an SkPaint, it's fastest to put it first.
 RECORD4(DrawBitmap, Optional<SkPaint>, paint,
                     ImmutableBitmap, bitmap,
diff --git a/tests/RecorderTest.cpp b/tests/RecorderTest.cpp
index 1ca9206..21a897c 100644
--- a/tests/RecorderTest.cpp
+++ b/tests/RecorderTest.cpp
@@ -49,6 +49,25 @@
     REPORTER_ASSERT(r, 1 == tally.count<SkRecords::DrawRect>());
 }
 
+// All of Skia will work fine without support for comment groups, but
+// Chrome's inspector can break.  This serves as a simple regression test.
+DEF_TEST(Recorder_CommentGroups, r) {
+    SkRecord record;
+    SkRecorder recorder(&record, 1920, 1080);
+
+    recorder.beginCommentGroup("test");
+        recorder.addComment("foo", "bar");
+        recorder.addComment("baz", "quux");
+    recorder.endCommentGroup();
+
+    Tally tally;
+    tally.apply(record);
+
+    REPORTER_ASSERT(r, 1 == tally.count<SkRecords::BeginCommentGroup>());
+    REPORTER_ASSERT(r, 2 == tally.count<SkRecords::AddComment>());
+    REPORTER_ASSERT(r, 1 == tally.count<SkRecords::EndCommentGroup>());
+}
+
 // Regression test for leaking refs held by optional arguments.
 DEF_TEST(Recorder_RefLeaking, r) {
     // We use SaveLayer to test: