blob: 5992da29e38894cd9ea671c16a5405f8966840dd [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
Haixia Shi0079afb2015-04-29 13:35:38 -070036static uint8_t scale_pixel(uint32_t neighbors, int sx, int sy, int scaling)
Haixia Shi95d680e2015-04-27 20:29:17 -070037{
Haixia Shic731c922015-04-30 14:59:08 -070038 /* Bitmasks of neighbor pixels */
39 enum {
40 NW = (1 << 8),
41 N = (1 << 7),
42 NE = (1 << 6),
43 W = (1 << 5),
44 C = (1 << 4),
45 E = (1 << 3),
46 SW = (1 << 2),
47 S = (1 << 1),
48 SE = (1 << 0),
49 };
50
Haixia Shi95d680e2015-04-27 20:29:17 -070051 /*
Haixia Shi0079afb2015-04-29 13:35:38 -070052 * Scale a pixel by a factor of |scaling|, based on the colors of the
53 * center pixel and the eight neighbor pixels on a 3x3 grid:
Haixia Shic731c922015-04-30 14:59:08 -070054 *
55 * NW | N | NE
56 * ---+---+---
57 * W | C | E
58 * ---+---+---
59 * SW | S | SE
60 *
61 * If the center pixel (C) is 1:
62 * Return 0 if a side pixel (N,W,E,S) and a corner pixel (NW,NE,SW,SE)
63 * disconnected from each other are both 1, and (sx, sy) falls on
64 * the corner of the center pixel furthest away from them, and all
65 * other pixels on the side of that corner are 0;
66 * Otherwise, return 1.
67 *
Haixia Shi95d680e2015-04-27 20:29:17 -070068 * If the center pixel is 0:
Haixia Shic731c922015-04-30 14:59:08 -070069 * Return 0 if all four side pixels are 1;
Haixia Shi0079afb2015-04-29 13:35:38 -070070 * Otherwise, return 1 if two adjacent side pixels are 1, and
Haixia Shi95d680e2015-04-27 20:29:17 -070071 * (sx, sy) falls inside the isosceles right triangle adjoining
Haixia Shi0079afb2015-04-29 13:35:38 -070072 * these two neighbor pixels and with legs of length |scaling - 1|,
73 * and either the corner pixel next to both side pixels is 0, or
74 * the other two corner pixels next to these side pixels are both 0.
Haixia Shi95d680e2015-04-27 20:29:17 -070075 */
Haixia Shic731c922015-04-30 14:59:08 -070076 if (neighbors & C) {
77 return !((sx == 0 && sy == 0 &&
78 ((neighbors & (S|SW|W|NW|N|NE)) == (S|NE) ||
79 (neighbors & (E|NE|N|NW|W|SW)) == (E|SW))) ||
80 (sx == scaling - 1 && sy == 0 &&
81 ((neighbors & (W|NW|N|NE|E|SE)) == (W|SE) ||
82 (neighbors & (S|SE|E|NE|N|NW)) == (S|NW))) ||
83 (sx == 0 && sy == scaling - 1 &&
84 ((neighbors & (N|NW|W|SW|S|SE)) == (N|SE) ||
85 (neighbors & (E|SE|S|SW|W|NW)) == (E|NW))) ||
86 (sx == scaling - 1 && sy == scaling - 1 &&
87 ((neighbors & (N|NE|E|SE|S|SW)) == (N|SW) ||
88 (neighbors & (W|SW|S|SE|E|NE)) == (W|NE))));
89 } else {
90 return ((neighbors & (N|W|E|S)) != (N|W|E|S) &&
91 ((sx < sy &&
92 (neighbors & (W|S)) == (W|S) &&
93 ((neighbors & SW) == 0 ||
94 (neighbors & (NW|SE)) == 0)) ||
95 (sy < sx &&
96 (neighbors & (N|E)) == (N|E) &&
97 ((neighbors & NE) == 0 ||
98 (neighbors & (NW|SE)) == 0)) ||
99 (sx + sy > scaling - 1 &&
100 (neighbors & (E|S)) == (E|S) &&
101 ((neighbors & SE) == 0 ||
102 (neighbors & (NE|SW)) == 0)) ||
103 (sx + sy < scaling - 1 &&
104 (neighbors & (N|W)) == (N|W) &&
105 ((neighbors & NW) == 0 ||
106 (neighbors & (NE|SW)) == 0))));
107 }
Haixia Shi95d680e2015-04-27 20:29:17 -0700108}
109
110static void scale_glyph(uint8_t *dst, const uint8_t *src, int scaling)
111{
112 for (int y = 0; y < GLYPH_HEIGHT; y++) {
113 for (int x = 0; x < GLYPH_WIDTH; x++) {
Haixia Shi0079afb2015-04-29 13:35:38 -0700114 uint32_t neighbors = 0;
115 for (int dy = -1; dy <= 1; dy++) {
116 for (int dx = -1; dx <= 1; dx++) {
117 neighbors <<= 1;
118 neighbors |= glyph_pixel(
119 src, x + dx, y + dy);
120 }
121 }
Haixia Shi95d680e2015-04-27 20:29:17 -0700122 for (int sy = 0; sy < scaling; sy++) {
123 uint8_t *dst_row = &dst[(y * scaling + sy) *
124 GLYPH_BYTES_PER_ROW * scaling];
125 for (int sx = 0; sx < scaling; sx++) {
126 if (scale_pixel(neighbors, sx, sy,
127 scaling)) {
128 set_bit(dst_row,
129 x * scaling + sx);
130 }
131 }
132 }
133 }
134 }
135}
136
137static void prescale_font(int scaling)
138{
139 int glyph_count = sizeof(glyphs) / (GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT);
140 glyph_size = GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT * scaling * scaling;
141 prescaled_glyphs = (uint8_t *)calloc(glyph_count, glyph_size);
142 for (int i = 0; i < glyph_count; i++) {
143 const uint8_t *src_glyph = glyphs[i];
144 uint8_t *dst_glyph = &prescaled_glyphs[i * glyph_size];
145 scale_glyph(dst_glyph, src_glyph, scaling);
146 }
147}
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700148
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700149void font_init(int scaling)
150{
151 font_scaling = scaling;
Haixia Shi95d680e2015-04-27 20:29:17 -0700152 if (scaling > 1) {
153 prescale_font(scaling);
154 }
155}
156
157void font_free()
158{
159 if (prescaled_glyphs) {
160 free(prescaled_glyphs);
161 prescaled_glyphs = NULL;
162 }
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700163}
164
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700165void font_get_size(uint32_t *char_width, uint32_t *char_height)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700166{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700167 *char_width = GLYPH_WIDTH * font_scaling;
168 *char_height = GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700169}
170
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700171void font_fillchar(uint32_t *dst_pointer, int dst_char_x, int dst_char_y,
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700172 int32_t pitch, uint32_t front_color, uint32_t back_color)
173{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700174 int dst_x = dst_char_x * GLYPH_WIDTH * font_scaling;
175 int dst_y = dst_char_y * GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700176
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700177 for (int j = 0; j < GLYPH_HEIGHT * font_scaling; j++)
178 for (int i = 0; i < GLYPH_WIDTH * font_scaling; i++)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700179 dst_pointer[dst_x + i + (dst_y + j) * pitch / 4] =
180 back_color;
181}
182
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700183void font_render(uint32_t *dst_pointer, int dst_char_x, int dst_char_y,
Dominik Behr00003502014-08-15 16:42:37 -0700184 int32_t pitch, uint32_t ch, uint32_t front_color,
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700185 uint32_t back_color)
186{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700187 int dst_x = dst_char_x * GLYPH_WIDTH * font_scaling;
188 int dst_y = dst_char_y * GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700189
Haixia Shi77955522015-04-22 15:21:03 -0700190 int32_t glyph_index = code_point_to_glyph_index(ch);
Zach Reiznera752c102015-04-15 15:03:11 -0700191 if (glyph_index < 0) {
Haixia Shi77955522015-04-22 15:21:03 -0700192 glyph_index = code_point_to_glyph_index(
Zach Reiznera752c102015-04-15 15:03:11 -0700193 UNICODE_REPLACEMENT_CHARACTER_CODE_POINT);
194 if (glyph_index < 0) {
195 return;
196 }
197 }
198
Haixia Shi95d680e2015-04-27 20:29:17 -0700199 const uint8_t *glyph;
200 if (font_scaling == 1) {
201 glyph = glyphs[glyph_index];
202 } else {
203 glyph = &prescaled_glyphs[glyph_index * glyph_size];
204 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700205
Haixia Shi95d680e2015-04-27 20:29:17 -0700206 for (int j = 0; j < GLYPH_HEIGHT * font_scaling; j++) {
207 const uint8_t *src_row =
208 &glyph[j * GLYPH_BYTES_PER_ROW * font_scaling];
209 for (int i = 0; i < GLYPH_WIDTH * font_scaling; i++) {
210 dst_pointer[dst_x + i + (dst_y + j) * pitch / 4] =
211 get_bit(src_row, i) ? front_color : back_color;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700212 }
Haixia Shi95d680e2015-04-27 20:29:17 -0700213 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700214}