Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 // vim:set ts=4 sts=4 sw=4 et cin:
2 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef GFX_SHARED_MEMORYSURFACE_H
8 #define GFX_SHARED_MEMORYSURFACE_H
10 #include "mozilla/ipc/Shmem.h"
11 #include "mozilla/ipc/SharedMemory.h"
13 #include "gfxASurface.h"
14 #include "gfxImageSurface.h"
15 #include "pratom.h"
17 typedef struct _cairo_user_data_key cairo_user_data_key_t;
19 struct SharedImageInfo {
20 int32_t width;
21 int32_t height;
22 gfxImageFormat format;
23 int32_t readCount;
24 };
26 inline SharedImageInfo*
27 GetShmInfoPtr(const mozilla::ipc::Shmem& aShmem)
28 {
29 return reinterpret_cast<SharedImageInfo*>
30 (aShmem.get<char>() + aShmem.Size<char>() - sizeof(SharedImageInfo));
31 }
33 extern const cairo_user_data_key_t SHM_KEY;
35 template <typename Base, typename Sub>
36 class gfxBaseSharedMemorySurface : public Base {
37 typedef mozilla::ipc::SharedMemory SharedMemory;
38 typedef mozilla::ipc::Shmem Shmem;
39 friend class gfxReusableSharedImageSurfaceWrapper;
41 public:
42 virtual ~gfxBaseSharedMemorySurface()
43 {
44 MOZ_COUNT_DTOR(gfxBaseSharedMemorySurface);
45 }
47 /**
48 * Return a new gfxSharedImageSurface around a shmem segment newly
49 * allocated by this function. |aAllocator| is the object used to
50 * allocate the new shmem segment. Null is returned if creating
51 * the surface failed.
52 *
53 * NB: the *caller* is responsible for freeing the Shmem allocated
54 * by this function.
55 */
56 template<class ShmemAllocator>
57 static already_AddRefed<Sub>
58 Create(ShmemAllocator* aAllocator,
59 const gfxIntSize& aSize,
60 gfxImageFormat aFormat,
61 SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC)
62 {
63 return Create<ShmemAllocator, false>(aAllocator, aSize, aFormat, aShmType);
64 }
66 /**
67 * Return a new gfxSharedImageSurface that wraps a shmem segment
68 * already created by the Create() above. Bad things will happen
69 * if an attempt is made to wrap any other shmem segment. Null is
70 * returned if creating the surface failed.
71 */
72 static already_AddRefed<Sub>
73 Open(const Shmem& aShmem)
74 {
75 SharedImageInfo* shmInfo = GetShmInfoPtr(aShmem);
76 gfxIntSize size(shmInfo->width, shmInfo->height);
77 if (!gfxASurface::CheckSurfaceSize(size))
78 return nullptr;
80 gfxImageFormat format = (gfxImageFormat)shmInfo->format;
81 long stride = gfxImageSurface::ComputeStride(size, format);
83 nsRefPtr<Sub> s =
84 new Sub(size,
85 stride,
86 format,
87 aShmem);
88 // We didn't create this Shmem and so don't free it on errors
89 return (s->CairoStatus() != 0) ? nullptr : s.forget();
90 }
92 template<class ShmemAllocator>
93 static already_AddRefed<Sub>
94 CreateUnsafe(ShmemAllocator* aAllocator,
95 const gfxIntSize& aSize,
96 gfxImageFormat aFormat,
97 SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC)
98 {
99 return Create<ShmemAllocator, true>(aAllocator, aSize, aFormat, aShmType);
100 }
102 Shmem& GetShmem() { return mShmem; }
104 static bool IsSharedImage(gfxASurface *aSurface)
105 {
106 return (aSurface
107 && aSurface->GetType() == gfxSurfaceType::Image
108 && aSurface->GetData(&SHM_KEY));
109 }
111 protected:
112 gfxBaseSharedMemorySurface(const gfxIntSize& aSize, long aStride,
113 gfxImageFormat aFormat,
114 const Shmem& aShmem)
115 : Base(aShmem.get<unsigned char>(), aSize, aStride, aFormat)
116 {
117 MOZ_COUNT_CTOR(gfxBaseSharedMemorySurface);
119 mShmem = aShmem;
120 this->SetData(&SHM_KEY, this, nullptr);
121 }
123 private:
124 void WriteShmemInfo()
125 {
126 SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
127 shmInfo->width = this->mSize.width;
128 shmInfo->height = this->mSize.height;
129 shmInfo->format = this->mFormat;
130 shmInfo->readCount = 0;
131 }
133 int32_t
134 ReadLock()
135 {
136 SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
137 return PR_ATOMIC_INCREMENT(&shmInfo->readCount);
138 }
140 int32_t
141 ReadUnlock()
142 {
143 SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
144 return PR_ATOMIC_DECREMENT(&shmInfo->readCount);
145 }
147 int32_t
148 GetReadCount()
149 {
150 SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
151 return shmInfo->readCount;
152 }
154 static size_t GetAlignedSize(const gfxIntSize& aSize, long aStride)
155 {
156 #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
157 return MOZ_ALIGN_WORD(sizeof(SharedImageInfo) + aSize.height * aStride);
158 }
160 template<class ShmemAllocator, bool Unsafe>
161 static already_AddRefed<Sub>
162 Create(ShmemAllocator* aAllocator,
163 const gfxIntSize& aSize,
164 gfxImageFormat aFormat,
165 SharedMemory::SharedMemoryType aShmType)
166 {
167 if (!gfxASurface::CheckSurfaceSize(aSize))
168 return nullptr;
170 Shmem shmem;
171 long stride = gfxImageSurface::ComputeStride(aSize, aFormat);
172 size_t size = GetAlignedSize(aSize, stride);
173 if (!Unsafe) {
174 if (!aAllocator->AllocShmem(size, aShmType, &shmem))
175 return nullptr;
176 } else {
177 if (!aAllocator->AllocUnsafeShmem(size, aShmType, &shmem))
178 return nullptr;
179 }
181 nsRefPtr<Sub> s =
182 new Sub(aSize, stride, aFormat, shmem);
183 if (s->CairoStatus() != 0) {
184 aAllocator->DeallocShmem(shmem);
185 return nullptr;
186 }
187 s->WriteShmemInfo();
188 return s.forget();
189 }
191 Shmem mShmem;
193 // Calling these is very bad, disallow it
194 gfxBaseSharedMemorySurface(const gfxBaseSharedMemorySurface&);
195 gfxBaseSharedMemorySurface& operator=(const gfxBaseSharedMemorySurface&);
196 };
198 #endif /* GFX_SHARED_MEMORYSURFACE_H */