- add sources.
[platform/framework/web/crosswalk.git] / src / ui / surface / transport_dib_gtk.cc
1 // Copyright (c) 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 #include "ui/surface/transport_dib.h"
6
7 // Desktop GTK Linux builds use the old-style SYSV SHM based DIBs.
8
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <sys/ipc.h>
12 #include <sys/shm.h>
13
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "skia/ext/platform_canvas.h"
17 #include "ui/base/x/x11_util.h"
18 #include "ui/gfx/size.h"
19
20 // The shmat system call uses this as it's invalid return address
21 static void *const kInvalidAddress = (void*) -1;
22
23 TransportDIB::TransportDIB()
24     : address_(kInvalidAddress),
25       x_shm_(0),
26       display_(NULL),
27       inflight_counter_(0),
28       detached_(false),
29       size_(0) {
30 }
31
32 TransportDIB::~TransportDIB() {
33   if (address_ != kInvalidAddress) {
34     shmdt(address_);
35     address_ = kInvalidAddress;
36   }
37
38   if (x_shm_) {
39     DCHECK(display_);
40     ui::DetachSharedMemory(display_, x_shm_);
41   }
42 }
43
44 // static
45 TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
46   const int shmkey = shmget(IPC_PRIVATE, size, 0600);
47   if (shmkey == -1) {
48     DLOG(ERROR) << "Failed to create SysV shared memory region"
49                 << " errno:" << errno;
50     return NULL;
51   } else {
52     VLOG(1) << "Created SysV shared memory region " << shmkey;
53   }
54
55   void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
56   // Here we mark the shared memory for deletion. Since we attached it in the
57   // line above, it doesn't actually get deleted but, if we crash, this means
58   // that the kernel will automatically clean it up for us.
59   shmctl(shmkey, IPC_RMID, 0);
60   if (address == kInvalidAddress)
61     return NULL;
62
63   TransportDIB* dib = new TransportDIB;
64
65   dib->key_.shmkey = shmkey;
66   dib->address_ = address;
67   dib->size_ = size;
68   return dib;
69 }
70
71 // static
72 TransportDIB* TransportDIB::Map(Handle handle) {
73   scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
74   if (!dib->Map())
75     return NULL;
76   return dib.release();
77 }
78
79 // static
80 TransportDIB* TransportDIB::CreateWithHandle(Handle shmkey) {
81   TransportDIB* dib = new TransportDIB;
82   dib->key_.shmkey = shmkey;
83   return dib;
84 }
85
86 // static
87 bool TransportDIB::is_valid_handle(Handle dib) {
88   return dib >= 0;
89 }
90
91 // static
92 bool TransportDIB::is_valid_id(Id id) {
93   return id.shmkey != -1;
94 }
95
96 skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
97   if ((address_ == kInvalidAddress && !Map()) || !VerifyCanvasSize(w, h))
98     return NULL;
99   return skia::CreatePlatformCanvas(w, h, true,
100                                     reinterpret_cast<uint8_t*>(memory()),
101                                     skia::RETURN_NULL_ON_FAILURE);
102 }
103
104 bool TransportDIB::Map() {
105   if (!is_valid_id(key_))
106     return false;
107   if (address_ != kInvalidAddress)
108     return true;
109
110   struct shmid_ds shmst;
111   if (shmctl(key_.shmkey, IPC_STAT, &shmst) == -1)
112     return false;
113
114   void* address = shmat(key_.shmkey, NULL /* desired address */, 0 /* flags */);
115   if (address == kInvalidAddress)
116     return false;
117
118   address_ = address;
119   size_ = shmst.shm_segsz;
120   return true;
121 }
122
123 void* TransportDIB::memory() const {
124   DCHECK_NE(address_, kInvalidAddress);
125   return address_;
126 }
127
128 TransportDIB::Id TransportDIB::id() const {
129   return key_;
130 }
131
132 TransportDIB::Handle TransportDIB::handle() const {
133   return key_.shmkey;
134 }
135
136 XID TransportDIB::MapToX(XDisplay* display) {
137   if (!x_shm_) {
138     x_shm_ = ui::AttachSharedMemory(display, key_.shmkey);
139     display_ = display;
140   }
141
142   return x_shm_;
143 }
144
145 void TransportDIB::DecreaseInFlightCounter() {
146   CHECK(inflight_counter_);
147   inflight_counter_--;
148   if (!inflight_counter_ && detached_)
149     delete this;
150 }
151
152 void TransportDIB::Detach() {
153   CHECK(!detached_);
154   detached_ = true;
155   if (!inflight_counter_)
156     delete this;
157 }
158