blob: e5afaaf202311ad10b946c84aa1af56f119cf099 [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <stdint.h>
8
9#include "font.h"
Zach Reiznera752c102015-04-15 15:03:11 -070010#include "glyphs.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070011#include "util.h"
12
Zach Reiznera752c102015-04-15 15:03:11 -070013#define UNICODE_REPLACEMENT_CHARACTER_CODE_POINT 0xFFFD
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070014
Haixia Shi95d680e2015-04-27 20:29:17 -070015static int font_scaling = 1;
16static int glyph_size = GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT;
17static uint8_t *prescaled_glyphs = NULL;
18
19static uint8_t get_bit(const uint8_t *buffer, int bit_offset)
20{
21 return (buffer[bit_offset / 8] >> (7 - (bit_offset % 8))) & 0x1;
22}
23
24static void set_bit(uint8_t *buffer, int bit_offset)
25{
26 buffer[bit_offset / 8] |= (0x1 << (7 - (bit_offset % 8)));
27}
28
29static uint8_t glyph_pixel(const uint8_t *glyph, int x, int y)
30{
31 if (x < 0 || x >= GLYPH_WIDTH || y < 0 || y >= GLYPH_HEIGHT)
32 return 0;
33 return get_bit(&glyph[y * GLYPH_BYTES_PER_ROW], x);
34}
35
36static uint8_t scale_pixel(uint8_t neighbors, int sx, int sy, int scaling)
37{
38 /*
39 * Scale a pixel by a factor of |scaling| using the following rules:
40 * If the center pixel is 1, always return 1;
41 * If the center pixel is 0:
42 * Return 0 if all four neighbor pixels are 1;
43 * Otherwise, return 1 if two adjacent neighbor pixels are 1, and
44 * (sx, sy) falls inside the isosceles right triangle adjoining
45 * these two neighbor pixels and with legs of length |scaling - 1|.
46 */
47 return ((neighbors & 0x1) ||
48 (neighbors != 0x1e &&
49 ((sy < sx && (neighbors & 0xc) == 0xc) ||
50 (sx < sy && (neighbors & 0x12) == 0x12) ||
51 (sx + sy > scaling - 1 && (neighbors & 0x14) == 0x14) ||
52 (sx + sy < scaling - 1 && (neighbors & 0xa) == 0xa))));
53}
54
55static void scale_glyph(uint8_t *dst, const uint8_t *src, int scaling)
56{
57 for (int y = 0; y < GLYPH_HEIGHT; y++) {
58 for (int x = 0; x < GLYPH_WIDTH; x++) {
59 uint8_t neighbors =
60 glyph_pixel(src, x, y) |
61 (glyph_pixel(src, x - 1, y) << 1) |
62 (glyph_pixel(src, x + 1, y) << 2) |
63 (glyph_pixel(src, x, y - 1) << 3) |
64 (glyph_pixel(src, x, y + 1) << 4);
65 for (int sy = 0; sy < scaling; sy++) {
66 uint8_t *dst_row = &dst[(y * scaling + sy) *
67 GLYPH_BYTES_PER_ROW * scaling];
68 for (int sx = 0; sx < scaling; sx++) {
69 if (scale_pixel(neighbors, sx, sy,
70 scaling)) {
71 set_bit(dst_row,
72 x * scaling + sx);
73 }
74 }
75 }
76 }
77 }
78}
79
80static void prescale_font(int scaling)
81{
82 int glyph_count = sizeof(glyphs) / (GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT);
83 glyph_size = GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT * scaling * scaling;
84 prescaled_glyphs = (uint8_t *)calloc(glyph_count, glyph_size);
85 for (int i = 0; i < glyph_count; i++) {
86 const uint8_t *src_glyph = glyphs[i];
87 uint8_t *dst_glyph = &prescaled_glyphs[i * glyph_size];
88 scale_glyph(dst_glyph, src_glyph, scaling);
89 }
90}
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -070091
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -070092void font_init(int scaling)
93{
94 font_scaling = scaling;
Haixia Shi95d680e2015-04-27 20:29:17 -070095 if (scaling > 1) {
96 prescale_font(scaling);
97 }
98}
99
100void font_free()
101{
102 if (prescaled_glyphs) {
103 free(prescaled_glyphs);
104 prescaled_glyphs = NULL;
105 }
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700106}
107
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700108void font_get_size(uint32_t *char_width, uint32_t *char_height)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700109{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700110 *char_width = GLYPH_WIDTH * font_scaling;
111 *char_height = GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700112}
113
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700114void font_fillchar(uint32_t *dst_pointer, int dst_char_x, int dst_char_y,
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700115 int32_t pitch, uint32_t front_color, uint32_t back_color)
116{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700117 int dst_x = dst_char_x * GLYPH_WIDTH * font_scaling;
118 int dst_y = dst_char_y * GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700119
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700120 for (int j = 0; j < GLYPH_HEIGHT * font_scaling; j++)
121 for (int i = 0; i < GLYPH_WIDTH * font_scaling; i++)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700122 dst_pointer[dst_x + i + (dst_y + j) * pitch / 4] =
123 back_color;
124}
125
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700126void font_render(uint32_t *dst_pointer, int dst_char_x, int dst_char_y,
Dominik Behr00003502014-08-15 16:42:37 -0700127 int32_t pitch, uint32_t ch, uint32_t front_color,
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700128 uint32_t back_color)
129{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700130 int dst_x = dst_char_x * GLYPH_WIDTH * font_scaling;
131 int dst_y = dst_char_y * GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700132
Haixia Shi77955522015-04-22 15:21:03 -0700133 int32_t glyph_index = code_point_to_glyph_index(ch);
Zach Reiznera752c102015-04-15 15:03:11 -0700134 if (glyph_index < 0) {
Haixia Shi77955522015-04-22 15:21:03 -0700135 glyph_index = code_point_to_glyph_index(
Zach Reiznera752c102015-04-15 15:03:11 -0700136 UNICODE_REPLACEMENT_CHARACTER_CODE_POINT);
137 if (glyph_index < 0) {
138 return;
139 }
140 }
141
Haixia Shi95d680e2015-04-27 20:29:17 -0700142 const uint8_t *glyph;
143 if (font_scaling == 1) {
144 glyph = glyphs[glyph_index];
145 } else {
146 glyph = &prescaled_glyphs[glyph_index * glyph_size];
147 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700148
Haixia Shi95d680e2015-04-27 20:29:17 -0700149 for (int j = 0; j < GLYPH_HEIGHT * font_scaling; j++) {
150 const uint8_t *src_row =
151 &glyph[j * GLYPH_BYTES_PER_ROW * font_scaling];
152 for (int i = 0; i < GLYPH_WIDTH * font_scaling; i++) {
153 dst_pointer[dst_x + i + (dst_y + j) * pitch / 4] =
154 get_bit(src_row, i) ? front_color : back_color;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700155 }
Haixia Shi95d680e2015-04-27 20:29:17 -0700156 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700157}