1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef SKIA_EXT_REFPTR_H_
6#define SKIA_EXT_REFPTR_H_
7
8#include "third_party/skia/include/core/SkRefCnt.h"
9
10namespace skia {
11
12// When creating/receiving a ref-counted pointer from Skia, wrap that pointer in
13// this class to avoid dealing with the ref-counting and prevent leaks/crashes
14// due to ref-counting bugs.
15//
16// Example of creating a new SkShader* and setting it on a SkPaint:
17//   skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::Create());
18//   paint.setShader(shader.get());
19//
20// When passing around a ref-counted pointer to methods outside of Skia, always
21// pass around the skia::RefPtr instead of the raw pointer. An example method
22// that takes a SkShader* parameter and saves the SkShader* in the class.
23//   void AMethodThatSavesAShader(const skia::RefPtr<SkShader>& shader) {
24//     member_refptr_ = shader;
25//   }
26//   skia::RefPtr<SkShader> member_refptr_;
27//
28// When returning a ref-counted pointer, also return the skia::RefPtr instead.
29// An example method that creates an SkShader* and returns it:
30//   skia::RefPtr<SkShader> MakeAShader() {
31//     return skia::AdoptRef(SkGradientShader::Create());
32//   }
33//
34// To take a scoped reference to an object whose references are all owned
35// by other objects (i.e. does not have one that needs to be adopted) use the
36// skia::SharePtr helper:
37//
38//   skia::RefPtr<SkShader> shader = skia::SharePtr(paint.getShader());
39//
40// Never call ref() or unref() on the underlying ref-counted pointer. If you
41// AdoptRef() the raw pointer immediately into a skia::RefPtr and always work
42// with skia::RefPtr instances instead, the ref-counting will be taken care of
43// for you.
44template<typename T>
45class RefPtr {
46 public:
47  RefPtr() : ptr_(NULL) {}
48
49  RefPtr(const RefPtr& other)
50      : ptr_(other.get()) {
51    SkSafeRef(ptr_);
52  }
53
54  template<typename U>
55  RefPtr(const RefPtr<U>& other)
56      : ptr_(other.get()) {
57    SkSafeRef(ptr_);
58  }
59
60  ~RefPtr() {
61    clear();
62  }
63
64  RefPtr& operator=(const RefPtr& other) {
65    SkRefCnt_SafeAssign(ptr_, other.get());
66    return *this;
67  }
68
69  template<typename U>
70  RefPtr& operator=(const RefPtr<U>& other) {
71    SkRefCnt_SafeAssign(ptr_, other.get());
72    return *this;
73  }
74
75  void clear() {
76    T* to_unref = ptr_;
77    ptr_ = NULL;
78    SkSafeUnref(to_unref);
79  }
80
81  T* get() const { return ptr_; }
82  T& operator*() const { return *ptr_; }
83  T* operator->() const { return ptr_; }
84
85  typedef T* RefPtr::*unspecified_bool_type;
86  operator unspecified_bool_type() const {
87    return ptr_ ? &RefPtr::ptr_ : NULL;
88  }
89
90 private:
91  T* ptr_;
92
93  // This function cannot be public because Skia starts its ref-counted
94  // objects at refcnt=1.  This makes it impossible to differentiate
95  // between a newly created object (that doesn't need to be ref'd) or an
96  // already existing object with one owner (that does need to be ref'd so that
97  // this RefPtr can also manage its lifetime).
98  explicit RefPtr(T* ptr) : ptr_(ptr) {}
99
100  template<typename U>
101  friend RefPtr<U> AdoptRef(U* ptr);
102
103  template<typename U>
104  friend RefPtr<U> SharePtr(U* ptr);
105};
106
107// For objects that have an unowned reference (such as newly created objects).
108template<typename T>
109RefPtr<T> AdoptRef(T* ptr) { return RefPtr<T>(ptr); }
110
111// For objects that are already owned. This doesn't take ownership of existing
112// references and adds a new one.
113template<typename T>
114RefPtr<T> SharePtr(T* ptr) { return RefPtr<T>(SkSafeRef(ptr)); }
115
116}  // namespace skia
117
118#endif  // SKIA_EXT_REFPTR_H_
119