blob: 8f3460ed00410f1ab0160f55c1d2832989621820 [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{
38 /*
Haixia Shi0079afb2015-04-29 13:35:38 -070039 * Scale a pixel by a factor of |scaling|, based on the colors of the
40 * center pixel and the eight neighbor pixels on a 3x3 grid:
Haixia Shi95d680e2015-04-27 20:29:17 -070041 * If the center pixel is 1, always return 1;
42 * If the center pixel is 0:
Haixia Shi0079afb2015-04-29 13:35:38 -070043 * Return 0 if all four side pixels (up, down, left, right) are 1;
44 * Otherwise, return 1 if two adjacent side pixels are 1, and
Haixia Shi95d680e2015-04-27 20:29:17 -070045 * (sx, sy) falls inside the isosceles right triangle adjoining
Haixia Shi0079afb2015-04-29 13:35:38 -070046 * these two neighbor pixels and with legs of length |scaling - 1|,
47 * and either the corner pixel next to both side pixels is 0, or
48 * the other two corner pixels next to these side pixels are both 0.
Haixia Shi95d680e2015-04-27 20:29:17 -070049 */
Haixia Shi0079afb2015-04-29 13:35:38 -070050 return ((neighbors & 0x10) ||
51 ((neighbors & 0xaa) != 0xaa &&
52 ((sx < sy &&
53 (neighbors & 0x22) == 0x22 &&
54 ((neighbors & 0x4) == 0x0 ||
55 (neighbors & 0x105) == 0x4)) ||
56 (sy < sx &&
57 (neighbors & 0x88) == 0x88 &&
58 ((neighbors & 0x40) == 0x0 ||
59 (neighbors & 0x141) == 0x40)) ||
60 (sx + sy > scaling - 1 &&
61 (neighbors & 0x0a) == 0x0a &&
62 ((neighbors & 0x1) == 0x0 ||
63 (neighbors & 0x45) == 0x1)) ||
64 (sx + sy < scaling - 1 &&
65 (neighbors & 0xa0) == 0xa0 &&
66 ((neighbors & 0x100) == 0x0 ||
67 (neighbors & 0x144) == 0x100)))));
Haixia Shi95d680e2015-04-27 20:29:17 -070068}
69
70static void scale_glyph(uint8_t *dst, const uint8_t *src, int scaling)
71{
72 for (int y = 0; y < GLYPH_HEIGHT; y++) {
73 for (int x = 0; x < GLYPH_WIDTH; x++) {
Haixia Shi0079afb2015-04-29 13:35:38 -070074 uint32_t neighbors = 0;
75 for (int dy = -1; dy <= 1; dy++) {
76 for (int dx = -1; dx <= 1; dx++) {
77 neighbors <<= 1;
78 neighbors |= glyph_pixel(
79 src, x + dx, y + dy);
80 }
81 }
Haixia Shi95d680e2015-04-27 20:29:17 -070082 for (int sy = 0; sy < scaling; sy++) {
83 uint8_t *dst_row = &dst[(y * scaling + sy) *
84 GLYPH_BYTES_PER_ROW * scaling];
85 for (int sx = 0; sx < scaling; sx++) {
86 if (scale_pixel(neighbors, sx, sy,
87 scaling)) {
88 set_bit(dst_row,
89 x * scaling + sx);
90 }
91 }
92 }
93 }
94 }
95}
96
97static void prescale_font(int scaling)
98{
99 int glyph_count = sizeof(glyphs) / (GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT);
100 glyph_size = GLYPH_BYTES_PER_ROW * GLYPH_HEIGHT * scaling * scaling;
101 prescaled_glyphs = (uint8_t *)calloc(glyph_count, glyph_size);
102 for (int i = 0; i < glyph_count; i++) {
103 const uint8_t *src_glyph = glyphs[i];
104 uint8_t *dst_glyph = &prescaled_glyphs[i * glyph_size];
105 scale_glyph(dst_glyph, src_glyph, scaling);
106 }
107}
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700108
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700109void font_init(int scaling)
110{
111 font_scaling = scaling;
Haixia Shi95d680e2015-04-27 20:29:17 -0700112 if (scaling > 1) {
113 prescale_font(scaling);
114 }
115}
116
117void font_free()
118{
119 if (prescaled_glyphs) {
120 free(prescaled_glyphs);
121 prescaled_glyphs = NULL;
122 }
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700123}
124
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700125void font_get_size(uint32_t *char_width, uint32_t *char_height)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700126{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700127 *char_width = GLYPH_WIDTH * font_scaling;
128 *char_height = GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700129}
130
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700131void font_fillchar(uint32_t *dst_pointer, int dst_char_x, int dst_char_y,
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700132 int32_t pitch, uint32_t front_color, uint32_t back_color)
133{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700134 int dst_x = dst_char_x * GLYPH_WIDTH * font_scaling;
135 int dst_y = dst_char_y * GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700136
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700137 for (int j = 0; j < GLYPH_HEIGHT * font_scaling; j++)
138 for (int i = 0; i < GLYPH_WIDTH * font_scaling; i++)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700139 dst_pointer[dst_x + i + (dst_y + j) * pitch / 4] =
140 back_color;
141}
142
Stéphane Marchesinf8807af2014-08-18 10:34:41 -0700143void font_render(uint32_t *dst_pointer, int dst_char_x, int dst_char_y,
Dominik Behr00003502014-08-15 16:42:37 -0700144 int32_t pitch, uint32_t ch, uint32_t front_color,
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700145 uint32_t back_color)
146{
Stéphane Marchesinaf4423b2014-08-13 16:39:24 -0700147 int dst_x = dst_char_x * GLYPH_WIDTH * font_scaling;
148 int dst_y = dst_char_y * GLYPH_HEIGHT * font_scaling;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700149
Haixia Shi77955522015-04-22 15:21:03 -0700150 int32_t glyph_index = code_point_to_glyph_index(ch);
Zach Reiznera752c102015-04-15 15:03:11 -0700151 if (glyph_index < 0) {
Haixia Shi77955522015-04-22 15:21:03 -0700152 glyph_index = code_point_to_glyph_index(
Zach Reiznera752c102015-04-15 15:03:11 -0700153 UNICODE_REPLACEMENT_CHARACTER_CODE_POINT);
154 if (glyph_index < 0) {
155 return;
156 }
157 }
158
Haixia Shi95d680e2015-04-27 20:29:17 -0700159 const uint8_t *glyph;
160 if (font_scaling == 1) {
161 glyph = glyphs[glyph_index];
162 } else {
163 glyph = &prescaled_glyphs[glyph_index * glyph_size];
164 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700165
Haixia Shi95d680e2015-04-27 20:29:17 -0700166 for (int j = 0; j < GLYPH_HEIGHT * font_scaling; j++) {
167 const uint8_t *src_row =
168 &glyph[j * GLYPH_BYTES_PER_ROW * font_scaling];
169 for (int i = 0; i < GLYPH_WIDTH * font_scaling; i++) {
170 dst_pointer[dst_x + i + (dst_y + j) * pitch / 4] =
171 get_bit(src_row, i) ? front_color : back_color;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700172 }
Haixia Shi95d680e2015-04-27 20:29:17 -0700173 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700174}