Fix Paint == comparison on Android.

The == operator was incorrect because of Androids use of
fGenerationID. This change moves the ID to the end of the
paint struct and omits it from the == comparison.
Review URL: http://codereview.appspot.com/5437098

git-svn-id: http://skia.googlecode.com/svn/trunk@2780 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index db11b33..3823481 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -877,9 +877,6 @@
     unsigned        fStyle : 2;
     unsigned        fTextEncoding : 2;  // 3 values
     unsigned        fHinting : 2;
-#ifdef SK_BUILD_FOR_ANDROID
-    uint32_t        fGenerationID;
-#endif
 
     SkDrawCacheProc    getDrawCacheProc() const;
     SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir,
@@ -905,6 +902,12 @@
     friend class SkDraw;
     friend class SkPDFDevice;
     friend class SkTextToPathIter;
+
+#ifdef SK_BUILD_FOR_ANDROID
+    // In order for the == operator to work properly this must be the last field
+    // in the struct so that we can do a memcmp to this field's offset.
+    uint32_t        fGenerationID;
+#endif
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 5ed22fd..ba99348 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -137,7 +137,12 @@
 }
 
 bool operator==(const SkPaint& a, const SkPaint& b) {
+#ifdef SK_BUILD_FOR_ANDROID
+    //assumes that fGenerationID is the last field in the struct
+    return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID));
+#else
     return !memcmp(&a, &b, sizeof(a));
+#endif
 }
 
 void SkPaint::reset() {
diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp
index 361da74..6350eb5 100644
--- a/tests/PaintTest.cpp
+++ b/tests/PaintTest.cpp
@@ -8,6 +8,60 @@
 #include "Test.h"
 #include "SkPath.h"
 #include "SkPaint.h"
+#include "SkLayerDrawLooper.h"
+#include "SkBlurMaskFilter.h"
+
+static void test_copy(skiatest::Reporter* reporter) {
+    SkPaint paint;
+    // set a few member variables
+    paint.setStyle(SkPaint::kStrokeAndFill_Style);
+    paint.setTextAlign(SkPaint::kLeft_Align);
+    paint.setStrokeWidth(SkIntToScalar(2));
+    // set a few pointers
+    SkLayerDrawLooper* looper = new SkLayerDrawLooper();
+    paint.setLooper(looper)->unref();
+    SkMaskFilter* mask = SkBlurMaskFilter::Create(1, SkBlurMaskFilter::kNormal_BlurStyle);
+    paint.setMaskFilter(mask)->unref();
+
+    // copy the paint using the copy constructor and check they are the same
+    SkPaint copiedPaint = paint;
+    REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+    // the copy constructor should preserve the Generation ID
+    int32_t paintGenID = paint.getGenerationID();
+    int32_t copiedPaintGenID = copiedPaint.getGenerationID();
+    REPORTER_ASSERT(reporter, paintGenID == copiedPaintGenID);
+    REPORTER_ASSERT(reporter, !memcmp(&paint, &copiedPaint, sizeof(paint)));
+#endif
+
+    // copy the paint using the equal operator and check they are the same
+    copiedPaint = paint;
+    REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+    // the equals operator should increment the Generation ID
+    REPORTER_ASSERT(reporter, paint.getGenerationID() == paintGenID);
+    REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+    copiedPaintGenID = copiedPaint.getGenerationID(); // reset to the new value
+    REPORTER_ASSERT(reporter, memcmp(&paint, &copiedPaint, sizeof(paint)));
+#endif
+
+    // clean the paint and check they are back to their initial states
+    SkPaint cleanPaint;
+    paint.reset();
+    copiedPaint.reset();
+    REPORTER_ASSERT(reporter, cleanPaint == paint);
+    REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+    // the reset function should increment the Generation ID
+    REPORTER_ASSERT(reporter, paint.getGenerationID() != paintGenID);
+    REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+    REPORTER_ASSERT(reporter, memcmp(&cleanPaint, &paint, sizeof(cleanPaint)));
+    REPORTER_ASSERT(reporter, memcmp(&cleanPaint, &copiedPaint, sizeof(cleanPaint)));
+#endif
+}
 
 // found and fixed for webkit: mishandling when we hit recursion limit on
 // mostly degenerate cubic flatness test
@@ -45,6 +99,7 @@
 
 static void TestPaint(skiatest::Reporter* reporter) {
     // TODO add general paint tests
+    test_copy(reporter);
 
     // regression tests
     regression_cubic(reporter);