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 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 50 const GRFont* gr_sys_font() 51 { 52 return gr_font; 53 } 54 55 int gr_measure(const GRFont* font, const char *s) 56 { 57 return font->char_width * strlen(s); 58 } 59 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 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 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 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 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 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 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 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 246 unsigned int gr_get_width(GRSurface* surface) { 247 if (surface == NULL) { 248 return 0; 249 } 250 return surface->width; 251 } 252 253 unsigned int gr_get_height(GRSurface* surface) { 254 if (surface == NULL) { 255 return 0; 256 } 257 return surface->height; 258 } 259 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 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 315 void gr_flip() { 316 gr_draw = gr_backend->Flip(); 317 } 318 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 350 void gr_exit() { 351 delete gr_backend; 352 } 353 354 int gr_fb_width() { 355 return gr_draw->width - 2 * overscan_offset_x; 356 } 357 358 int gr_fb_height() { 359 return gr_draw->height - 2 * overscan_offset_y; 360 } 361 362 void gr_fb_blank(bool blank) { 363 gr_backend->Blank(blank); 364 } 365