Merge tomhudson and mtklein SkPaint shrinking approaches.

I think this is cherry picking the best parts of both our CLs.  We've got dirty bit tracking from Tom's, picture format stability from Mike's, etc.  Paints are typically 1/3 their original size when flattened in the dictionary.

bench_record on my desktop looks promising.  Generally, looks faster.  (Best in monospace.)
a/b   skp                               before  after
0.83  desk_techcrunch.skp               0.29    0.24
0.83  tabl_gamedeksiam.skp              0.52    0.43
0.87  desk_carsvg.skp                   0.4     0.35
0.87  desk_googlehome.skp               0.038   0.033
0.87  desk_pokemonwiki.skp              3.9     3.4
0.88  desk_fontwipe.skp                 0.0089  0.0078
0.88  desk_googlespreadsheet.skp        0.16    0.14
0.89  desk_jsfiddlebigcar.skp           0.027   0.024
0.89  desk_tigersvg.skp                 0.038   0.034
0.89  desk_weather.skp                  0.19    0.17
0.89  tabl_engadget.skp                 0.37    0.33
0.89  tabl_googleblog.skp               0.28    0.25
0.9   desk_facebook.skp                 0.2     0.18
0.91  desk_mapsvg.skp                   0.45    0.41
0.91  desk_youtube.skp                  0.22    0.2
0.92  desk_forecastio.skp               0.12    0.11
0.92  desk_googlespreadsheetdashed.skp  0.49    0.45
0.92  desk_gws.skp                      0.13    0.12
0.92  desk_pinterest.skp                0.037   0.034
0.92  desk_twitter.skp                  0.25    0.23
0.92  tabl_culturalsolutions.skp        0.26    0.24
0.92  tabl_gspro.skp                    0.072   0.066
0.92  tabl_mercurynews.skp              0.26    0.24
0.93  desk_booking.skp                  0.46    0.43
0.93  desk_chalkboard.skp               0.28    0.26
0.93  desk_linkedin.skp                 0.14    0.13
0.93  desk_mobilenews.skp               0.28    0.26
0.93  tabl_cuteoverload.skp             0.46    0.43
0.93  tabl_deviantart.skp               0.15    0.14
0.93  tabl_gmail.skp                    0.029   0.027
0.93  tabl_googlecalendar.skp           0.15    0.14
0.93  tabl_mlb.skp                      0.15    0.14
0.94  desk_blogger.skp                  0.18    0.17
0.94  desk_jsfiddlehumperclip.skp       0.034   0.032
0.94  desk_wordpress.skp                0.33    0.31
0.94  desk_wowwiki.skp                  0.94    0.88
0.94  desk_yahooanswers.skp             0.17    0.16
0.94  desk_youtubetvvideo.skp           0.017   0.016
0.94  tabl_sahadan.skp                  0.093   0.087
0.94  tabl_worldjournal.skp             0.35    0.33
0.95  desk_css3gradients.skp            0.21    0.2
0.95  desk_gmailthread.skp              0.19    0.18
0.95  tabl_cnet.skp                     0.42    0.4
0.95  tabl_mozilla.skp                  1.9     1.8
0.95  tabl_pravda.skp                   0.19    0.18
0.96  mobi_wikipedia.skp                0.55    0.53
0.96  tabl_cnn.skp                      0.48    0.46
0.96  tabl_nofolo.skp                   0.05    0.048
0.97  desk_googleplus.skp               0.29    0.28
0.97  tabl_frantzen.skp                 0.059   0.057
0.97  tabl_onlinewsj.skp                0.38    0.37
0.97  tabl_slashdot.skp                 0.1     0.097
0.97  tabl_vnexpress.skp                0.29    0.28
0.99  desk_amazon.skp                   0.088   0.087
1     desk_baidu.skp                    0.097   0.099
1     desk_ebay.skp                     0.18    0.18
1     desk_espn.skp                     0.24    0.24
1     desk_oldinboxapp.skp              0.026   0.026
1     desk_rectangletransition.skp      0.014   0.014
1     desk_samoasvg.skp                 0.23    0.24
1     desk_yahoogames.skp               0.029   0.029
1     desk_yahoosports.skp              0.0033  0.0033
1     desk_youtubetvbrowse.skp          0.01    0.01
1     tabl_androidpolice.skp            0.65    0.65
1     tabl_digg.skp                     0.33    0.33
1     tabl_hsfi.skp                     0.32    0.32
1     tabl_nytimes.skp                  0.22    0.22
1     tabl_techmeme.skp                 0.069   0.072
1     tabl_ukwsj.skp                    0.35    0.35
1.1   desk_sfgate.skp                   0.25    0.28


BUG=skia:2190,skia:2194

Committed: http://code.google.com/p/skia/source/detail?r=13487

Committed: http://code.google.com/p/skia/source/detail?r=13496

R=tomhudson@google.com, reed@google.com, mtklein@google.com, robertphillips@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/158913005

git-svn-id: http://skia.googlecode.com/svn/trunk@13536 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp
index 3210e77..e7954b9 100644
--- a/tests/PaintTest.cpp
+++ b/tests/PaintTest.cpp
@@ -11,8 +11,11 @@
 #include "SkPaint.h"
 #include "SkPath.h"
 #include "SkRandom.h"
+#include "SkReadBuffer.h"
 #include "SkTypeface.h"
 #include "SkUtils.h"
+#include "SkWriteBuffer.h"
+#include "SkXfermode.h"
 #include "Test.h"
 
 static size_t uni_to_utf8(const SkUnichar src[], void* dst, int count) {
@@ -251,3 +254,40 @@
        test_cmap(reporter);
     }
 }
+
+#define ASSERT(expr) REPORTER_ASSERT(r, expr)
+
+DEF_TEST(Paint_FlatteningTraits, r) {
+    SkPaint paint;
+    paint.setColor(0x00AABBCC);
+    paint.setTextScaleX(1.0f);  // Encoded despite being the default value.
+    paint.setTextSize(19);
+    paint.setXfermode(SkXfermode::Create(SkXfermode::kModulate_Mode))->unref();
+    paint.setLooper(NULL);  // Ignored.
+
+    SkWriteBuffer writer;
+    SkPaint::FlatteningTraits::Flatten(writer, paint);
+    const size_t expectedBytesWritten = sizeof(void*) == 8 ? 48 : 40;
+    ASSERT(expectedBytesWritten == writer.bytesWritten());
+
+    const uint32_t* written = writer.getWriter32()->contiguousArray();
+    SkASSERT(written != NULL);
+    ASSERT(*written == ((1<<0) | (1<<2) | (1<<3) | (1<<9)));  // Dirty bits for our 4.
+
+    SkReadBuffer reader(written, writer.bytesWritten());
+    SkPaint other;
+    SkPaint::FlatteningTraits::Unflatten(reader, &other);
+    ASSERT(reader.offset() == writer.bytesWritten());
+
+    // No matter the encoding, these must always hold.
+    ASSERT(other.getColor()      == paint.getColor());
+    ASSERT(other.getTextScaleX() == paint.getTextScaleX());
+    ASSERT(other.getTextSize()   == paint.getTextSize());
+    ASSERT(other.getLooper()     == paint.getLooper());
+
+    // We have to be a little looser and compare just the modes.  Pointers might not be the same.
+    SkXfermode::Mode otherMode, paintMode;
+    ASSERT(other.getXfermode()->asMode(&otherMode));
+    ASSERT(paint.getXfermode()->asMode(&paintMode));
+    ASSERT(otherMode == paintMode);
+}