1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "graphics.h"
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <memory>
24 
25 #include "font_10x18.h"
26 #include "graphics_adf.h"
27 #include "graphics_drm.h"
28 #include "graphics_fbdev.h"
29 #include "minui/minui.h"
30 
31 static GRFont* gr_font = NULL;
32 static MinuiBackend* gr_backend = nullptr;
33 
34 static int overscan_percent = OVERSCAN_PERCENT;
35 static int overscan_offset_x = 0;
36 static int overscan_offset_y = 0;
37 
38 static unsigned char gr_current_r = 255;
39 static unsigned char gr_current_g = 255;
40 static unsigned char gr_current_b = 255;
41 static unsigned char gr_current_a = 255;
42 
43 static GRSurface* gr_draw = NULL;
44 
outside(int x,int y)45 static bool outside(int x, int y)
46 {
47     return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
48 }
49 
gr_sys_font()50 const GRFont* gr_sys_font()
51 {
52     return gr_font;
53 }
54 
gr_measure(const GRFont * font,const char * s)55 int gr_measure(const GRFont* font, const char *s)
56 {
57     return font->char_width * strlen(s);
58 }
59 
gr_font_size(const GRFont * font,int * x,int * y)60 void gr_font_size(const GRFont* font, int *x, int *y)
61 {
62     *x = font->char_width;
63     *y = font->char_height;
64 }
65 
text_blend(unsigned char * src_p,int src_row_bytes,unsigned char * dst_p,int dst_row_bytes,int width,int height)66 static void text_blend(unsigned char* src_p, int src_row_bytes,
67                        unsigned char* dst_p, int dst_row_bytes,
68                        int width, int height)
69 {
70     for (int j = 0; j < height; ++j) {
71         unsigned char* sx = src_p;
72         unsigned char* px = dst_p;
73         for (int i = 0; i < width; ++i) {
74             unsigned char a = *sx++;
75             if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255;
76             if (a == 255) {
77                 *px++ = gr_current_r;
78                 *px++ = gr_current_g;
79                 *px++ = gr_current_b;
80                 px++;
81             } else if (a > 0) {
82                 *px = (*px * (255-a) + gr_current_r * a) / 255;
83                 ++px;
84                 *px = (*px * (255-a) + gr_current_g * a) / 255;
85                 ++px;
86                 *px = (*px * (255-a) + gr_current_b * a) / 255;
87                 ++px;
88                 ++px;
89             } else {
90                 px += 4;
91             }
92         }
93         src_p += src_row_bytes;
94         dst_p += dst_row_bytes;
95     }
96 }
97 
gr_text(const GRFont * font,int x,int y,const char * s,bool bold)98 void gr_text(const GRFont* font, int x, int y, const char *s, bool bold)
99 {
100     if (!font->texture || gr_current_a == 0) return;
101 
102     bold = bold && (font->texture->height != font->char_height);
103 
104     x += overscan_offset_x;
105     y += overscan_offset_y;
106 
107     unsigned char ch;
108     while ((ch = *s++)) {
109         if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break;
110 
111         if (ch < ' ' || ch > '~') {
112             ch = '?';
113         }
114 
115         unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
116                                (bold ? font->char_height * font->texture->row_bytes : 0);
117         unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
118 
119         text_blend(src_p, font->texture->row_bytes,
120                    dst_p, gr_draw->row_bytes,
121                    font->char_width, font->char_height);
122 
123         x += font->char_width;
124     }
125 }
126 
gr_texticon(int x,int y,GRSurface * icon)127 void gr_texticon(int x, int y, GRSurface* icon) {
128     if (icon == NULL) return;
129 
130     if (icon->pixel_bytes != 1) {
131         printf("gr_texticon: source has wrong format\n");
132         return;
133     }
134 
135     x += overscan_offset_x;
136     y += overscan_offset_y;
137 
138     if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return;
139 
140     unsigned char* src_p = icon->data;
141     unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
142 
143     text_blend(src_p, icon->row_bytes,
144                dst_p, gr_draw->row_bytes,
145                icon->width, icon->height);
146 }
147 
gr_color(unsigned char r,unsigned char g,unsigned char b,unsigned char a)148 void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
149 {
150 #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
151     gr_current_r = b;
152     gr_current_g = g;
153     gr_current_b = r;
154     gr_current_a = a;
155 #else
156     gr_current_r = r;
157     gr_current_g = g;
158     gr_current_b = b;
159     gr_current_a = a;
160 #endif
161 }
162 
gr_clear()163 void gr_clear()
164 {
165     if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
166         memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
167     } else {
168         unsigned char* px = gr_draw->data;
169         for (int y = 0; y < gr_draw->height; ++y) {
170             for (int x = 0; x < gr_draw->width; ++x) {
171                 *px++ = gr_current_r;
172                 *px++ = gr_current_g;
173                 *px++ = gr_current_b;
174                 px++;
175             }
176             px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
177         }
178     }
179 }
180 
gr_fill(int x1,int y1,int x2,int y2)181 void gr_fill(int x1, int y1, int x2, int y2)
182 {
183     x1 += overscan_offset_x;
184     y1 += overscan_offset_y;
185 
186     x2 += overscan_offset_x;
187     y2 += overscan_offset_y;
188 
189     if (outside(x1, y1) || outside(x2-1, y2-1)) return;
190 
191     unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes;
192     if (gr_current_a == 255) {
193         int x, y;
194         for (y = y1; y < y2; ++y) {
195             unsigned char* px = p;
196             for (x = x1; x < x2; ++x) {
197                 *px++ = gr_current_r;
198                 *px++ = gr_current_g;
199                 *px++ = gr_current_b;
200                 px++;
201             }
202             p += gr_draw->row_bytes;
203         }
204     } else if (gr_current_a > 0) {
205         int x, y;
206         for (y = y1; y < y2; ++y) {
207             unsigned char* px = p;
208             for (x = x1; x < x2; ++x) {
209                 *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255;
210                 ++px;
211                 *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255;
212                 ++px;
213                 *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255;
214                 ++px;
215                 ++px;
216             }
217             p += gr_draw->row_bytes;
218         }
219     }
220 }
221 
gr_blit(GRSurface * source,int sx,int sy,int w,int h,int dx,int dy)222 void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
223     if (source == NULL) return;
224 
225     if (gr_draw->pixel_bytes != source->pixel_bytes) {
226         printf("gr_blit: source has wrong format\n");
227         return;
228     }
229 
230     dx += overscan_offset_x;
231     dy += overscan_offset_y;
232 
233     if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
234 
235     unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
236     unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
237 
238     int i;
239     for (i = 0; i < h; ++i) {
240         memcpy(dst_p, src_p, w * source->pixel_bytes);
241         src_p += source->row_bytes;
242         dst_p += gr_draw->row_bytes;
243     }
244 }
245 
gr_get_width(GRSurface * surface)246 unsigned int gr_get_width(GRSurface* surface) {
247     if (surface == NULL) {
248         return 0;
249     }
250     return surface->width;
251 }
252 
gr_get_height(GRSurface * surface)253 unsigned int gr_get_height(GRSurface* surface) {
254     if (surface == NULL) {
255         return 0;
256     }
257     return surface->height;
258 }
259 
gr_init_font(const char * name,GRFont ** dest)260 int gr_init_font(const char* name, GRFont** dest) {
261     GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
262     if (font == nullptr) {
263         return -1;
264     }
265 
266     int res = res_create_alpha_surface(name, &(font->texture));
267     if (res < 0) {
268         free(font);
269         return res;
270     }
271 
272     // The font image should be a 96x2 array of character images.  The
273     // columns are the printable ASCII characters 0x20 - 0x7f.  The
274     // top row is regular text; the bottom row is bold.
275     font->char_width = font->texture->width / 96;
276     font->char_height = font->texture->height / 2;
277 
278     *dest = font;
279 
280     return 0;
281 }
282 
gr_init_font(void)283 static void gr_init_font(void)
284 {
285     int res = gr_init_font("font", &gr_font);
286     if (res == 0) {
287         return;
288     }
289 
290     printf("failed to read font: res=%d\n", res);
291 
292 
293     // fall back to the compiled-in font.
294     gr_font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
295     gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
296     gr_font->texture->width = font.width;
297     gr_font->texture->height = font.height;
298     gr_font->texture->row_bytes = font.width;
299     gr_font->texture->pixel_bytes = 1;
300 
301     unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
302     gr_font->texture->data = bits;
303 
304     unsigned char data;
305     unsigned char* in = font.rundata;
306     while((data = *in++)) {
307         memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
308         bits += (data & 0x7f);
309     }
310 
311     gr_font->char_width = font.char_width;
312     gr_font->char_height = font.char_height;
313 }
314 
gr_flip()315 void gr_flip() {
316   gr_draw = gr_backend->Flip();
317 }
318 
gr_init()319 int gr_init() {
320   gr_init_font();
321 
322   auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() };
323   gr_draw = backend->Init();
324 
325   if (!gr_draw) {
326     backend = std::make_unique<MinuiBackendDrm>();
327     gr_draw = backend->Init();
328   }
329 
330   if (!gr_draw) {
331     backend = std::make_unique<MinuiBackendFbdev>();
332     gr_draw = backend->Init();
333   }
334 
335   if (!gr_draw) {
336     return -1;
337   }
338 
339   gr_backend = backend.release();
340 
341   overscan_offset_x = gr_draw->width * overscan_percent / 100;
342   overscan_offset_y = gr_draw->height * overscan_percent / 100;
343 
344   gr_flip();
345   gr_flip();
346 
347   return 0;
348 }
349 
gr_exit()350 void gr_exit() {
351   delete gr_backend;
352 }
353 
gr_fb_width()354 int gr_fb_width() {
355   return gr_draw->width - 2 * overscan_offset_x;
356 }
357 
gr_fb_height()358 int gr_fb_height() {
359   return gr_draw->height - 2 * overscan_offset_y;
360 }
361 
gr_fb_blank(bool blank)362 void gr_fb_blank(bool blank) {
363   gr_backend->Blank(blank);
364 }
365