Skip to content

Commit 52c51ba

Browse files
committed
Creates a filled and outlined font
1 parent cd2142a commit 52c51ba

File tree

2 files changed

+88
-39
lines changed

2 files changed

+88
-39
lines changed

src_c/font.c

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -540,28 +540,11 @@ font_set_strikethrough(PyObject *self, PyObject *arg)
540540

541541
static int
542542
_create_font_surface(TTF_Font *font, PyObject *text, int antialias,
543-
PyObject *fg_rgba_obj, PyObject *bg_rgba_obj,
543+
SDL_Color foreg, SDL_Color backg, int draw_backg,
544544
int wraplength, SDL_Surface **dst_surf)
545545
{
546-
Uint8 rgba[] = {0, 0, 0, 0};
547546
const char *astring = "";
548547

549-
// 글꼴 생성
550-
if (!pg_RGBAFromObjEx(fg_rgba_obj, rgba, PG_COLOR_HANDLE_ALL)) {
551-
return 0; // exception already set
552-
}
553-
554-
SDL_Color foreg = {rgba[0], rgba[1], rgba[2], SDL_ALPHA_OPAQUE};
555-
/* might be overridden right below, with an explicit background color */
556-
SDL_Color backg = {0, 0, 0, SDL_ALPHA_OPAQUE};
557-
558-
if (bg_rgba_obj != Py_None) {
559-
if (!pg_RGBAFromObjEx(bg_rgba_obj, rgba, PG_COLOR_HANDLE_ALL)) {
560-
return 0; // exception already set.
561-
}
562-
backg = (SDL_Color){rgba[0], rgba[1], rgba[2], SDL_ALPHA_OPAQUE};
563-
}
564-
565548
if (!PyUnicode_Check(text) && !PyBytes_Check(text) && text != Py_None) {
566549
PyErr_Format(PyExc_TypeError, "text must be a unicode or bytes");
567550
return 0;
@@ -602,7 +585,7 @@ _create_font_surface(TTF_Font *font, PyObject *text, int antialias,
602585
*dst_surf = PG_CreateSurface(0, height, PG_PIXELFORMAT_XRGB8888);
603586
}
604587
else { /* normal case */
605-
if (antialias && bg_rgba_obj == Py_None) {
588+
if (antialias && !draw_backg) {
606589
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
607590
*dst_surf = TTF_RenderUTF8_Blended_Wrapped(font, astring, foreg,
608591
wraplength);
@@ -627,7 +610,7 @@ _create_font_surface(TTF_Font *font, PyObject *text, int antialias,
627610
#endif
628611
/* If an explicit background was provided and the rendering options
629612
resolve to Render_Solid, that needs to be explicitly handled. */
630-
if (*dst_surf != NULL && bg_rgba_obj != Py_None) {
613+
if (*dst_surf != NULL && draw_backg) {
631614
SDL_SetColorKey(*dst_surf, 0, 0);
632615
(*dst_surf)->format->palette->colors[0].r = backg.r;
633616
(*dst_surf)->format->palette->colors[0].g = backg.g;
@@ -655,8 +638,12 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
655638
PyObject *text, *final;
656639
PyObject *fg_rgba_obj, *bg_rgba_obj = Py_None;
657640
SDL_Surface *surf = NULL;
641+
SDL_Surface *outline_surf = NULL;
658642
int wraplength = 0;
659643
TTF_Font *font = PyFont_AsFont(self);
644+
int outline_size = ((PyFontObject *)self)->outline_size;
645+
SDL_Color outline_color = ((PyFontObject *)self)->outline_color;
646+
Uint8 rgba[] = {0, 0, 0, 0};
660647

661648
if (!PgFont_GenerationCheck(self)) {
662649
return RAISE_FONT_QUIT_ERROR()
@@ -671,14 +658,74 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
671658
return NULL;
672659
}
673660

674-
if (!_create_font_surface(font, text, antialias, fg_rgba_obj, bg_rgba_obj,
661+
// 글꼴 생성
662+
if (!pg_RGBAFromObjEx(fg_rgba_obj, rgba, PG_COLOR_HANDLE_ALL)) {
663+
return 0; // exception already set
664+
}
665+
666+
SDL_Color foreg = {rgba[0], rgba[1], rgba[2], SDL_ALPHA_OPAQUE};
667+
SDL_Color backg = {0, 0, 0, SDL_ALPHA_OPAQUE};
668+
int draw_backg = 1;
669+
/* might be overridden right below, with an explicit background color */
670+
671+
if (bg_rgba_obj != Py_None) {
672+
if (!pg_RGBAFromObjEx(bg_rgba_obj, rgba, PG_COLOR_HANDLE_ALL)) {
673+
return 0; // exception already set.
674+
}
675+
backg = (SDL_Color){rgba[0], rgba[1], rgba[2], SDL_ALPHA_OPAQUE};
676+
}
677+
else {
678+
draw_backg = 0;
679+
}
680+
681+
if (!_create_font_surface(font, text, antialias, foreg, backg, draw_backg,
675682
wraplength, &surf)) {
676683
return NULL;
677684
}
678685

679-
final = (PyObject *)pgSurface_New(surf);
686+
SDL_Surface *filled_with_outline_surf = NULL;
687+
688+
if (outline_size > 0) {
689+
TTF_SetFontOutline(font, outline_size);
690+
691+
if (!_create_font_surface(font, text, antialias, outline_color, backg,
692+
draw_backg, wraplength, &outline_surf)) {
693+
return NULL;
694+
}
695+
696+
TTF_SetFontOutline(font, 0);
697+
698+
filled_with_outline_surf = PG_CreateSurface(
699+
outline_surf->w, outline_surf->h, SDL_PIXELFORMAT_RGBA32);
700+
701+
// `surf` and `outline_surf` are **NOT** the same size.
702+
SDL_Rect outlinerect;
703+
outlinerect.x = filled_with_outline_surf->w / 2 - outline_surf->w / 2;
704+
outlinerect.y = filled_with_outline_surf->h / 2 - outline_surf->h / 2;
705+
outlinerect.w = outline_surf->w;
706+
outlinerect.h = outline_surf->h;
707+
SDL_Rect fillrect;
708+
fillrect.x = filled_with_outline_surf->w / 2 - surf->w / 2;
709+
fillrect.y = filled_with_outline_surf->h / 2 - surf->h / 2;
710+
fillrect.w = surf->w;
711+
fillrect.h = surf->h;
712+
SDL_BlitSurface(surf, NULL, filled_with_outline_surf, &fillrect);
713+
SDL_BlitSurface(outline_surf, NULL, filled_with_outline_surf,
714+
&outlinerect);
715+
716+
final = (PyObject *)pgSurface_New(filled_with_outline_surf);
717+
}
718+
else {
719+
final = (PyObject *)pgSurface_New(surf);
720+
}
721+
680722
if (final == NULL) {
681723
SDL_FreeSurface(surf);
724+
if (outline_surf != NULL)
725+
SDL_FreeSurface(outline_surf);
726+
727+
if (filled_with_outline_surf != NULL)
728+
SDL_FreeSurface(filled_with_outline_surf);
682729
}
683730
return final;
684731
}
@@ -1309,6 +1356,9 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds)
13091356
Py_DECREF(obj);
13101357
self->font = font;
13111358
self->ptsize = fontsize;
1359+
self->outline_size = 0;
1360+
SDL_Color init_color = {0, 0, 0, SDL_ALPHA_OPAQUE};
1361+
self->outline_color = init_color;
13121362
self->ttf_init_generation = current_ttf_generation;
13131363

13141364
return 0;

test/font_test.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -981,8 +981,15 @@ def test_font_property_should_raise_exception_after_quit(self):
981981
("italic", True),
982982
("underline", True),
983983
("strikethrough", True),
984-
("outline_size", 2),
985-
("outline_color", (20, 0, 6)),
984+
("outline_size", 5),
985+
(
986+
"outline_color",
987+
(
988+
255,
989+
0,
990+
255,
991+
),
992+
),
986993
]
987994
skip_properties = set()
988995
version = pygame.font.get_sdl_ttf_version()
@@ -1045,7 +1052,7 @@ def setUp(self):
10451052
self.screen = pygame.display.set_mode((600, 200))
10461053
self.screen.fill((255, 255, 255))
10471054
pygame.display.flip()
1048-
self.f = pygame_font.Font(None, 32)
1055+
self.f = pygame_font.Font(None, 96)
10491056

10501057
def abort(self):
10511058
if self.screen is not None:
@@ -1059,8 +1066,8 @@ def query(
10591066
underline=False,
10601067
strikethrough=False,
10611068
antialiase=False,
1062-
outline_size=2,
1063-
outline_color=(20, 0, 6),
1069+
outline_size=0,
1070+
outline_color=(0, 0, 0),
10641071
):
10651072
if self.aborted:
10661073
return False
@@ -1072,13 +1079,7 @@ def query(
10721079
screen.fill((255, 255, 255))
10731080
pygame.display.flip()
10741081
if not (
1075-
bold
1076-
or italic
1077-
or underline
1078-
or strikethrough
1079-
or antialiase
1080-
or outline_size
1081-
or outline_color
1082+
bold or italic or underline or strikethrough or antialiase or outline_size
10821083
):
10831084
text = "normal"
10841085
else:
@@ -1095,8 +1096,6 @@ def query(
10951096
modes.append("antialiased")
10961097
if outline_size:
10971098
modes.append("outline_size")
1098-
if outline_color:
1099-
modes.append("outline_color")
11001099
text = f"{'-'.join(modes)} (y/n):"
11011100
f.set_bold(bold)
11021101
f.set_italic(italic)
@@ -1144,10 +1143,10 @@ def test_antialiase(self):
11441143
self.assertTrue(self.query(antialiase=True))
11451144

11461145
def test_outline_size(self):
1147-
self.assertTrue(self.query(outline_size=2))
1146+
self.assertTrue(self.query(outline_size=1, outline_color=(255, 0, 255)))
11481147

1149-
def test_outline_color(self):
1150-
self.assertTrue(self.query(outline_color=(20, 0, 6)))
1148+
def test_outline_size_huge(self):
1149+
self.assertTrue(self.query(outline_size=10, outline_color=(0, 0, 255)))
11511150

11521151
def test_bold_antialiase(self):
11531152
self.assertTrue(self.query(bold=True, antialiase=True))

0 commit comments

Comments
 (0)