mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-02 12:44:01 +02:00
Fix preview rendering when height of previewed font greater than cell height
This commit is contained in:
@@ -128,13 +128,18 @@ def render_face_sample(font: Descriptor, opts: Options, dpi_x: float, dpi_y: flo
|
||||
'psname': face.postscript_name(),
|
||||
'features': get_features(face.get_features()),
|
||||
'applied_features': face.applied_features(),
|
||||
'cell_width': 0, 'cell_height': 0, 'canvas_height': 0, 'canvas_width': width,
|
||||
}
|
||||
if is_variable(font):
|
||||
ns = get_named_style(face)
|
||||
if ns:
|
||||
metadata['variable_named_style'] = ns
|
||||
metadata['variable_axis_map'] = get_axis_map(face)
|
||||
return face.render_sample_text(SAMPLE_TEXT, width, height, opts.foreground.rgb), metadata
|
||||
bitmap, cell_width, cell_height = face.render_sample_text(SAMPLE_TEXT, width, height, opts.foreground.rgb)
|
||||
metadata['cell_width'] = cell_width
|
||||
metadata['cell_height'] = cell_height
|
||||
metadata['canvas_height'] = len(bitmap) // (4 *width)
|
||||
return bitmap, metadata
|
||||
|
||||
|
||||
def render_family_sample(
|
||||
@@ -230,8 +235,8 @@ def showcase(family: str = 'family="Fira Code"') -> None:
|
||||
ss = screen_size_function()()
|
||||
width = ss.cell_width * ss.cols
|
||||
height = 5 * ss.cell_height
|
||||
bitmap = render_face_sample(desc, opts, float(q['dpi_x']), float(q['dpi_y']), width, height)[0]
|
||||
display_bitmap(bitmap, width, height)
|
||||
bitmap, m = render_face_sample(desc, opts, float(q['dpi_x']), float(q['dpi_y']), width, height)
|
||||
display_bitmap(bitmap, m['canvas_width'], m['canvas_height'])
|
||||
|
||||
|
||||
def test_render(spec: str = 'family="Fira Code"', width: int = 1560, height: int = 116, font_size: float = 12, dpi: float = 288) -> None:
|
||||
@@ -240,5 +245,5 @@ def test_render(spec: str = 'family="Fira Code"', width: int = 1560, height: int
|
||||
opts.font_size = font_size
|
||||
opts.foreground = to_color('white')
|
||||
desc = get_font_files(opts)['medium']
|
||||
bitmap = render_face_sample(desc, opts, float(dpi), float(dpi), width, height)[0]
|
||||
display_bitmap(bitmap, width, height)
|
||||
bitmap, m = render_face_sample(desc, opts, float(dpi), float(dpi), width, height)
|
||||
display_bitmap(bitmap, m['canvas_width'], m['canvas_height'])
|
||||
|
||||
@@ -200,8 +200,7 @@ func (self *face_panel) draw_screen() (err error) {
|
||||
y := self.render_lines(2, lines...)
|
||||
|
||||
num_lines_per_font := (int(sz.HeightCells) - y - 1) - 2
|
||||
num_lines_needed := int(math.Ceil(100. / float64(sz.WidthCells)))
|
||||
num_lines := max(1, min(num_lines_per_font, num_lines_needed))
|
||||
num_lines := max(1, num_lines_per_font)
|
||||
key := faces_preview_key{settings: self.settings, width: int(sz.WidthCells * sz.CellWidth), height: int(sz.CellHeight) * num_lines}
|
||||
self.current_preview_key = key
|
||||
self.preview_cache_mutex.Lock()
|
||||
@@ -232,13 +231,14 @@ func (self *face_panel) draw_screen() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
num_lines = int(math.Ceil(float64(preview.Canvas_height) / float64(sz.CellHeight)))
|
||||
if int(sz.HeightCells)-y >= num_lines+2 {
|
||||
y += 1
|
||||
y++
|
||||
lp.MoveCursorTo(1, y+1)
|
||||
self.handler.draw_preview_header(0)
|
||||
y++
|
||||
lp.MoveCursorTo(1, y+1)
|
||||
self.handler.graphics_manager.display_image(0, preview.Path, key.width, key.height)
|
||||
self.handler.graphics_manager.display_image(0, preview.Path, preview.Canvas_width, preview.Canvas_height)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ func (self *faces) draw_screen() (err error) {
|
||||
lp.QueueWriteString(str)
|
||||
|
||||
num_lines_per_font := ((int(sz.HeightCells) - y - 1) / 4) - 2
|
||||
num_lines_needed := int(math.Ceil(100. / float64(sz.WidthCells)))
|
||||
num_lines := max(1, min(num_lines_per_font, num_lines_needed))
|
||||
num_lines := max(1, num_lines_per_font)
|
||||
key := faces_preview_key{settings: self.settings, width: int(sz.WidthCells * sz.CellWidth), height: int(sz.CellHeight) * num_lines}
|
||||
self.preview_cache_mutex.Lock()
|
||||
defer self.preview_cache_mutex.Unlock()
|
||||
@@ -74,6 +73,8 @@ func (self *faces) draw_screen() (err error) {
|
||||
|
||||
slot := 0
|
||||
d := func(setting, title string) {
|
||||
r := previews[setting]
|
||||
num_lines := int(math.Ceil(float64(r.Canvas_height) / float64(sz.CellHeight)))
|
||||
if int(sz.HeightCells)-y < num_lines+1 {
|
||||
return
|
||||
}
|
||||
@@ -82,7 +83,7 @@ func (self *faces) draw_screen() (err error) {
|
||||
lp.QueueWriteString(str)
|
||||
if y+num_lines < int(sz.HeightCells) {
|
||||
lp.MoveCursorTo(1, y+1)
|
||||
self.handler.graphics_manager.display_image(slot, previews[setting].Path, key.width, key.height)
|
||||
self.handler.graphics_manager.display_image(slot, r.Path, r.Canvas_width, r.Canvas_height)
|
||||
slot++
|
||||
y += num_lines + 1
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ package choose_fonts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"kitty/tools/tui/loop"
|
||||
"kitty/tools/tui/readline"
|
||||
"kitty/tools/utils"
|
||||
"kitty/tools/utils/style"
|
||||
"kitty/tools/wcswidth"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
@@ -19,6 +19,11 @@ type preview_cache_key struct {
|
||||
width, height int
|
||||
}
|
||||
|
||||
type preview_cache_value struct {
|
||||
path string
|
||||
width, height int
|
||||
}
|
||||
|
||||
type FontList struct {
|
||||
rl *readline.Readline
|
||||
family_list FamilyList
|
||||
@@ -27,13 +32,13 @@ type FontList struct {
|
||||
resolved_faces_from_kitty_conf ResolvedFaces
|
||||
handler *handler
|
||||
variable_data_requested_for *utils.Set[string]
|
||||
preview_cache map[preview_cache_key]string
|
||||
preview_cache map[preview_cache_key]preview_cache_value
|
||||
preview_cache_mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (self *FontList) initialize(h *handler) error {
|
||||
self.handler = h
|
||||
self.preview_cache = make(map[preview_cache_key]string)
|
||||
self.preview_cache = make(map[preview_cache_key]preview_cache_value)
|
||||
self.rl = readline.New(h.lp, readline.RlInit{DontMarkPrompts: true, Prompt: "Family: "})
|
||||
self.variable_data_requested_for = utils.NewSet[string](256)
|
||||
return nil
|
||||
@@ -133,7 +138,6 @@ func (self *FontList) draw_preview(x, y int, sz loop.ScreenSize) (err error) {
|
||||
self.handler.draw_preview_header(x)
|
||||
y++
|
||||
height_cells -= 2
|
||||
height_cells = min(height_cells, int(math.Ceil(100./float64(width_cells))))
|
||||
self.handler.lp.MoveCursorTo(x+1, y+1)
|
||||
key := preview_cache_key{
|
||||
family: self.family_list.CurrentFamily(), width: int(sz.CellWidth) * width_cells, height: int(sz.CellHeight) * height_cells,
|
||||
@@ -143,10 +147,10 @@ func (self *FontList) draw_preview(x, y int, sz loop.ScreenSize) (err error) {
|
||||
}
|
||||
self.preview_cache_mutex.Lock()
|
||||
defer self.preview_cache_mutex.Unlock()
|
||||
img_path := self.preview_cache[key]
|
||||
switch img_path {
|
||||
cc := self.preview_cache[key]
|
||||
switch cc.path {
|
||||
case "":
|
||||
self.preview_cache[key] = "requested"
|
||||
self.preview_cache[key] = preview_cache_value{path: "requested"}
|
||||
go func() {
|
||||
var r map[string]RenderedSampleTransmit
|
||||
self.handler.set_worker_error(kitty_font_backend.query("render_family_samples", map[string]any{
|
||||
@@ -155,14 +159,14 @@ func (self *FontList) draw_preview(x, y int, sz loop.ScreenSize) (err error) {
|
||||
}, &r))
|
||||
self.preview_cache_mutex.Lock()
|
||||
defer self.preview_cache_mutex.Unlock()
|
||||
self.preview_cache[key] = r["font_family"].Path
|
||||
self.preview_cache[key] = preview_cache_value{path: r["font_family"].Path, width: r["font_family"].Canvas_width, height: r["font_family"].Canvas_height}
|
||||
self.handler.lp.WakeupMainThread()
|
||||
}()
|
||||
return
|
||||
case "requested":
|
||||
return
|
||||
}
|
||||
self.handler.graphics_manager.display_image(0, img_path, key.width, key.height)
|
||||
self.handler.graphics_manager.display_image(0, cc.path, cc.width, cc.height)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,10 @@ type RenderedSampleTransmit struct {
|
||||
Applied_features map[string]string `json:"applied_features"`
|
||||
Variable_named_style NamedStyle `json:"variable_named_style"`
|
||||
Variable_axis_map map[string]float64 `json:"variable_axis_map"`
|
||||
Cell_width int `json:"cell_width"`
|
||||
Cell_height int `json:"cell_height"`
|
||||
Canvas_width int `json:"canvas_width"`
|
||||
Canvas_height int `json:"canvas_height"`
|
||||
}
|
||||
|
||||
func (self RenderedSampleTransmit) default_axis_values() (ans map[string]float64) {
|
||||
|
||||
@@ -749,11 +749,13 @@ render_sample_text(CTFace *self, PyObject *args) {
|
||||
CTFontRef font = self->ct_font;
|
||||
PyObject *ptext;
|
||||
if (!PyArg_ParseTuple(args, "Ukk|k", &ptext, &canvas_width, &canvas_height, &fg)) return NULL;
|
||||
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
||||
if (!pbuf) return NULL;
|
||||
unsigned int cell_width, cell_height, baseline, underline_position, underline_thickness, strikethrough_position, strikethrough_thickness;
|
||||
cell_metrics((PyObject*)self, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness, &strikethrough_position, &strikethrough_thickness);
|
||||
size_t num_chars = PyUnicode_GET_LENGTH(ptext);
|
||||
int num_chars_per_line = canvas_width / cell_width, num_of_lines = (int)ceil((float)num_chars / (float)num_chars_per_line);
|
||||
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
|
||||
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
||||
if (!pbuf) return NULL;
|
||||
RAII_ALLOC(unichar, chars, calloc(sizeof(unichar), num_chars));
|
||||
if (!chars) return PyErr_NoMemory();
|
||||
for (size_t i = 0; i < num_chars; i++) chars[i] = PyUnicode_READ_CHAR(ptext, i);
|
||||
@@ -786,8 +788,7 @@ render_sample_text(CTFace *self, PyObject *args) {
|
||||
p[0] = r; p[1] = g; p[2] = b; p[3] = s[0];
|
||||
}
|
||||
end:
|
||||
Py_INCREF(pbuf);
|
||||
return pbuf;
|
||||
return Py_BuildValue("OII", pbuf, cell_width, cell_height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ class Face:
|
||||
def identify_for_debug(self) -> str: ...
|
||||
def postscript_name(self) -> str: ...
|
||||
def set_size(self, sz_in_pts: float, dpi_x: float, dpi_y: float) -> None: ...
|
||||
def render_sample_text(self, text: str, width: int, height: int, fg_color: int = 0xffffff) -> bytes: ...
|
||||
def render_sample_text(self, text: str, width: int, height: int, fg_color: int = 0xffffff) -> Tuple[bytes, int, int]: ...
|
||||
def get_variation(self) -> Optional[Dict[str, float]]: ...
|
||||
def get_features(self) -> Dict[str, Optional[FeatureData]]: ...
|
||||
def applied_features(self) -> Dict[str, str]: ...
|
||||
@@ -476,7 +476,7 @@ class CTFace:
|
||||
def identify_for_debug(self) -> str: ...
|
||||
def postscript_name(self) -> str: ...
|
||||
def set_size(self, sz_in_pts: float, dpi_x: float, dpi_y: float) -> None: ...
|
||||
def render_sample_text(self, text: str, width: int, height: int, fg_color: int = 0xffffff) -> bytes: ...
|
||||
def render_sample_text(self, text: str, width: int, height: int, fg_color: int = 0xffffff) -> Tuple[bytes, int, int]: ...
|
||||
def get_variation(self) -> Optional[Dict[str, float]]: ...
|
||||
def get_features(self) -> Dict[str, Optional[FeatureData]]: ...
|
||||
def applied_features(self) -> Dict[str, str]: ...
|
||||
|
||||
@@ -964,10 +964,12 @@ render_sample_text(Face *self, PyObject *args) {
|
||||
unsigned long fg = 0xffffff;
|
||||
PyObject *ptext;
|
||||
if (!PyArg_ParseTuple(args, "Ukk|k", &ptext, &canvas_width, &canvas_height, &fg)) return NULL;
|
||||
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
||||
if (!pbuf) return NULL;
|
||||
unsigned int cell_width, cell_height, baseline, underline_position, underline_thickness, strikethrough_position, strikethrough_thickness;
|
||||
cell_metrics((PyObject*)self, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness, &strikethrough_position, &strikethrough_thickness);
|
||||
int num_chars_per_line = canvas_width / cell_width, num_of_lines = (int)ceil((float)PyUnicode_GET_LENGTH(ptext) / (float)num_chars_per_line);
|
||||
canvas_height = MIN(canvas_height, num_of_lines * cell_height);
|
||||
RAII_PyObject(pbuf, PyBytes_FromStringAndSize(NULL, sizeof(pixel) * canvas_width * canvas_height));
|
||||
if (!pbuf) return NULL;
|
||||
pixel *canvas = (pixel*)PyBytes_AS_STRING(pbuf);
|
||||
memset(canvas, 0, PyBytes_GET_SIZE(pbuf));
|
||||
if (cell_width > canvas_width) goto end;
|
||||
@@ -996,8 +998,7 @@ render_sample_text(Face *self, PyObject *args) {
|
||||
p[0] = r; p[1] = g; p[2] = b; p[3] = a;
|
||||
}
|
||||
end:
|
||||
Py_INCREF(pbuf);
|
||||
return pbuf;
|
||||
return Py_BuildValue("OII", pbuf, cell_width, cell_height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user