Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et ft=cpp : */
3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
18 #include <fcntl.h>
19 #include <linux/fb.h>
20 #include <linux/kd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/ioctl.h>
24 #include <sys/mman.h>
25 #include <sys/types.h>
26 #include <unistd.h>
28 #include <vector>
30 #include "android/log.h"
32 #include "Framebuffer.h"
33 #include "gfxContext.h"
34 #include "gfxImageSurface.h"
35 #include "gfxUtils.h"
36 #include "mozilla/FileUtils.h"
37 #include "nsTArray.h"
38 #include "nsRegion.h"
40 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
42 using namespace std;
44 namespace mozilla {
46 namespace Framebuffer {
48 static int sFd = -1;
49 static size_t sMappedSize;
50 static struct fb_var_screeninfo sVi;
51 static size_t sActiveBuffer;
52 typedef vector<nsRefPtr<gfxImageSurface> > BufferVector;
53 BufferVector* sBuffers;
54 static gfxIntSize *sScreenSize = nullptr;
56 BufferVector& Buffers() { return *sBuffers; }
58 bool
59 SetGraphicsMode()
60 {
61 ScopedClose fd(open("/dev/tty0", O_RDWR | O_SYNC));
62 if (0 > fd.get()) {
63 // This is non-fatal; post-Cupcake kernels don't have tty0.
64 LOG("No /dev/tty0?");
65 } else if (ioctl(fd.get(), KDSETMODE, (void*) KD_GRAPHICS)) {
66 LOG("Error setting graphics mode on /dev/tty0");
67 return false;
68 }
69 return true;
70 }
72 bool
73 Open()
74 {
75 if (0 <= sFd)
76 return true;
78 if (!SetGraphicsMode())
79 return false;
81 ScopedClose fd(open("/dev/graphics/fb0", O_RDWR));
82 if (0 > fd.get()) {
83 LOG("Error opening framebuffer device");
84 return false;
85 }
87 struct fb_fix_screeninfo fi;
88 if (0 > ioctl(fd.get(), FBIOGET_FSCREENINFO, &fi)) {
89 LOG("Error getting fixed screeninfo");
90 return false;
91 }
93 if (0 > ioctl(fd.get(), FBIOGET_VSCREENINFO, &sVi)) {
94 LOG("Error getting variable screeninfo");
95 return false;
96 }
98 sMappedSize = fi.smem_len;
99 void* mem = mmap(0, sMappedSize, PROT_READ | PROT_WRITE, MAP_SHARED,
100 fd.rwget(), 0);
101 if (MAP_FAILED == mem) {
102 LOG("Error mmap'ing framebuffer");
103 return false;
104 }
106 sFd = fd.get();
107 fd.forget();
109 // The android porting doc requires a /dev/graphics/fb0 device
110 // that's double buffered with r5g6b5 format. Hence the
111 // hard-coded numbers here.
112 gfxImageFormat format = gfxImageFormat::RGB16_565;
113 if (!sScreenSize) {
114 sScreenSize = new gfxIntSize(sVi.xres, sVi.yres);
115 }
116 long stride = fi.line_length;
117 size_t numFrameBytes = stride * sScreenSize->height;
119 sBuffers = new BufferVector(2);
120 unsigned char* data = static_cast<unsigned char*>(mem);
121 for (size_t i = 0; i < 2; ++i, data += numFrameBytes) {
122 memset(data, 0, numFrameBytes);
123 Buffers()[i] = new gfxImageSurface(data, *sScreenSize, stride, format);
124 }
126 // Clear the framebuffer to a known state.
127 Present(nsIntRect());
129 return true;
130 }
132 bool
133 GetSize(nsIntSize *aScreenSize) {
134 // If the framebuffer has been opened, we should always have the size.
135 if (sScreenSize) {
136 *aScreenSize = *sScreenSize;
137 return true;
138 }
140 ScopedClose fd(open("/dev/graphics/fb0", O_RDWR));
141 if (0 > fd.get()) {
142 LOG("Error opening framebuffer device");
143 return false;
144 }
146 if (0 > ioctl(fd.get(), FBIOGET_VSCREENINFO, &sVi)) {
147 LOG("Error getting variable screeninfo");
148 return false;
149 }
151 sScreenSize = new gfxIntSize(sVi.xres, sVi.yres);
152 *aScreenSize = *sScreenSize;
153 return true;
154 }
156 void
157 Close()
158 {
159 if (0 > sFd)
160 return;
162 munmap(Buffers()[0]->Data(), sMappedSize);
163 delete sBuffers;
164 sBuffers = nullptr;
165 delete sScreenSize;
166 sScreenSize = nullptr;
168 close(sFd);
169 sFd = -1;
170 }
172 gfxASurface*
173 BackBuffer()
174 {
175 return Buffers()[!sActiveBuffer];
176 }
178 static gfxASurface*
179 FrontBuffer()
180 {
181 return Buffers()[sActiveBuffer];
182 }
184 void
185 Present(const nsIntRegion& aUpdated)
186 {
187 sActiveBuffer = !sActiveBuffer;
189 sVi.yres_virtual = sVi.yres * 2;
190 sVi.yoffset = sActiveBuffer * sVi.yres;
191 sVi.bits_per_pixel = 16;
192 if (ioctl(sFd, FBIOPUT_VSCREENINFO, &sVi) < 0) {
193 LOG("Error presenting front buffer");
194 }
196 nsRefPtr<gfxContext> ctx = new gfxContext(BackBuffer());
197 gfxUtils::PathFromRegion(ctx, aUpdated);
198 ctx->Clip();
199 ctx->SetSource(FrontBuffer());
200 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
201 ctx->Paint(1.0);
202 }
204 } // namespace Framebuffer
206 } // namespace mozilla