use new template class SkTLazy for deferred paint initialization
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 6 Apr 2011 20:17:29 +0000 (20:17 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 6 Apr 2011 20:17:29 +0000 (20:17 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@1070 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkTLazy.h [new file with mode: 0644]
src/core/SkCanvas.cpp

diff --git a/include/core/SkTLazy.h b/include/core/SkTLazy.h
new file mode 100644 (file)
index 0000000..94e6415
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+
+#ifndef SkTLazy_DEFINED
+#define SkTLazy_DEFINED
+
+#include "SkTypes.h"
+
+/**
+ *  Efficient way to defer allocating/initializing a class until it is needed
+ *  (if ever).
+ */
+template <typename T> class SkTLazy {
+public:
+    SkTLazy() : fPtr(NULL) {}
+
+    explicit SkTLazy(const T* src) : fPtr(NULL) {
+        if (src) {
+            fPtr = new (fStorage) T(*src);
+        }
+    }
+
+    SkTLazy(const SkTLazy<T>& src) : fPtr(NULL) {
+        const T* ptr = src.get();
+        if (ptr) {
+            fPtr = new (fStorage) T(*ptr);
+        }
+    }
+
+    ~SkTLazy() {
+        if (fPtr) {
+            fPtr->~T();
+        }
+    }
+
+    /**
+     *  Copy src into this, and return a pointer to a copy of it. Note this
+     *  will always return the same pointer, so if it is called on a lazy that
+     *  has already been initialized, then this will copy over the previous
+     *  contents.
+     */
+    T* set(const T& src) {
+        if (fPtr) {
+            *fPtr = src;
+        } else {
+            fPtr = new (fStorage) T(src);
+        }
+        return fPtr;
+    }
+    
+    /**
+     *  Returns either NULL, or a copy of the object that was passed to
+     *  set() or the constructor.
+     */
+    T* get() const { return fPtr; }
+    
+private:
+    T*   fPtr; // NULL or fStorage
+    char fStorage[sizeof(T)];
+};
+
+#endif
+
index e518b45..a0e7e6e 100644 (file)
@@ -24,6 +24,7 @@
 #include "SkScalarCompare.h"
 #include "SkShape.h"
 #include "SkTemplates.h"
+#include "SkTLazy.h"
 #include "SkUtils.h"
 #include <new>
 
@@ -1363,7 +1364,7 @@ public:
     SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
         SkDevice::TextFlags flags;
         if (device->filterTextFlags(paint, &flags)) {
-            SkPaint* newPaint = new (fStorage) SkPaint(paint);
+            SkPaint* newPaint = fLazy.set(paint);
             newPaint->setFlags(flags.fFlags);
             newPaint->setHinting(flags.fHinting);
             fPaint = newPaint;
@@ -1372,19 +1373,11 @@ public:
         }
     }
 
-    ~SkDeviceFilteredPaint() {
-        if (reinterpret_cast<SkPaint*>(fStorage) == fPaint) {
-            fPaint->~SkPaint();
-        }
-    }
-
     const SkPaint& paint() const { return *fPaint; }
 
 private:
-    // points to either fStorage or the caller's paint
-    const SkPaint*  fPaint;
-    // we rely on the fPaint above to ensure proper alignment of fStorage
-    char            fStorage[sizeof(SkPaint)];
+    const SkPaint*   fPaint;
+    SkTLazy<SkPaint> fLazy;
 };
 
 void SkCanvas::drawText(const void* text, size_t byteLength,