netsurf/gtk/font_pango.c
Vincent Sanders c105738fa3 Change LOG() macro to be varadic
This changes the LOG macro to be varadic removing the need for all
callsites to have double bracketing and allows for future improvement
on how we use the logging macros.

The callsites were changed with coccinelle and the changes checked by
hand. Compile tested for several frontends but not all.

A formatting annotation has also been added which allows the compiler
to check the parameters and types passed to the logging.
2015-05-28 16:08:46 +01:00

315 lines
8.4 KiB
C

/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Font handling (GTK implementation).
*
* Pango is used handle and render fonts.
*/
#include <assert.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include "utils/utils.h"
#include "utils/log.h"
#include "utils/nsoption.h"
#include "desktop/font.h"
#include "gtk/font_pango.h"
#include "gtk/plotters.h"
static bool nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width);
static bool nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
static bool nsfont_split(const plot_font_style_t *style,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
const struct font_functions nsfont = {
nsfont_width,
nsfont_position_in_string,
nsfont_split
};
static PangoContext *nsfont_pango_context = NULL;
static PangoLayout *nsfont_pango_layout = NULL;
static inline void nsfont_pango_check(void)
{
if (nsfont_pango_context == NULL) {
LOG("Creating nsfont_pango_context.");
nsfont_pango_context = gdk_pango_context_get();
}
if (nsfont_pango_layout == NULL) {
LOG("Creating nsfont_pango_layout.");
nsfont_pango_layout = pango_layout_new(nsfont_pango_context);
}
}
/**
* Measure the width of a string.
*
* \param fstyle plot style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param width updated to width of string[0..length)
* \return true on success, false on error and error reported
*/
bool nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
PangoFontDescription *desc;
if (length == 0) {
*width = 0;
return true;
}
nsfont_pango_check();
desc = nsfont_style_to_description(fstyle);
pango_layout_set_font_description(nsfont_pango_layout, desc);
pango_layout_set_text(nsfont_pango_layout, string, length);
pango_layout_get_pixel_size(nsfont_pango_layout, width, 0);
pango_font_description_free(desc);
/* LOG(("fstyle: %p string:\"%.*s\", length: %u, width: %dpx",
fstyle, length, string, length, *width));
*/
return true;
}
/**
* Find the position in a string where an x coordinate falls.
*
* \param fstyle plot style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param x x coordinate to search for
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*/
bool nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
int index;
PangoFontDescription *desc;
PangoRectangle pos;
nsfont_pango_check();
desc = nsfont_style_to_description(fstyle);
pango_layout_set_font_description(nsfont_pango_layout, desc);
pango_layout_set_text(nsfont_pango_layout, string, length);
if (pango_layout_xy_to_index(nsfont_pango_layout, x * PANGO_SCALE,
0, &index, 0) == FALSE)
index = length;
pango_layout_index_to_pos(nsfont_pango_layout, index, &pos);
pango_font_description_free(desc);
*char_offset = index;
*actual_x = PANGO_PIXELS(pos.x);
return true;
}
/**
* Find where to split a string to make it fit a width.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string, in bytes
* \param x width available
* \param char_offset updated to offset in string of actual_x, [1..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*
* On exit, char_offset indicates first character after split point.
*
* Note: char_offset of 0 should never be returned.
*
* Returns:
* char_offset giving split point closest to x, where actual_x <= x
* else
* char_offset giving split point closest to x, where actual_x > x
*
* Returning char_offset == length means no split possible
*/
bool nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
int index = length;
PangoFontDescription *desc;
PangoContext *context;
PangoLayout *layout;
PangoLayoutLine *line;
desc = nsfont_style_to_description(fstyle);
context = gdk_pango_context_get();
layout = pango_layout_new(context);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, string, length);
/* Limit width of layout to the available width */
pango_layout_set_width(layout, x * PANGO_SCALE);
/* Request word wrapping */
pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
/* Prevent pango treating linebreak characters as line breaks */
pango_layout_set_single_paragraph_mode(layout, TRUE);
/* Obtain the second line of the layout (if there is one) */
line = pango_layout_get_line(layout, 1);
if (line != NULL) {
/* Pango split the text. The line's start_index indicates the
* start of the character after the line break. */
index = line->start_index;
}
g_object_unref(layout);
g_object_unref(context);
pango_font_description_free(desc);
*char_offset = index;
/* Obtain the pixel offset of the split character */
nsfont_width(fstyle, string, index, actual_x);
return true;
}
/**
* Render a string.
*
* \param x x coordinate
* \param y y coordinate
* \param string UTF-8 string to measure
* \param length length of string
* \param fstyle plot style for this text
* \return true on success, false on error and error reported
*/
bool nsfont_paint(int x, int y, const char *string, size_t length,
const plot_font_style_t *fstyle)
{
PangoFontDescription *desc;
PangoLayout *layout;
PangoLayoutLine *line;
if (length == 0)
return true;
desc = nsfont_style_to_description(fstyle);
layout = pango_cairo_create_layout(current_cr);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, string, length);
line = pango_layout_get_line(layout, 0);
cairo_move_to(current_cr, x, y);
nsgtk_set_colour(fstyle->foreground);
pango_cairo_show_layout_line(current_cr, line);
pango_font_description_free(desc);
return true;
}
/**
* Convert a plot style to a PangoFontDescription.
*
* \param fstyle plot style for this text
* \return A new Pango font description
*/
PangoFontDescription *nsfont_style_to_description(
const plot_font_style_t *fstyle)
{
unsigned int size;
PangoFontDescription *desc;
PangoStyle style = PANGO_STYLE_NORMAL;
switch (fstyle->family) {
case PLOT_FONT_FAMILY_SERIF:
desc = pango_font_description_from_string(nsoption_charp(font_serif));
break;
case PLOT_FONT_FAMILY_MONOSPACE:
desc = pango_font_description_from_string(nsoption_charp(font_mono));
break;
case PLOT_FONT_FAMILY_CURSIVE:
desc = pango_font_description_from_string(nsoption_charp(font_cursive));
break;
case PLOT_FONT_FAMILY_FANTASY:
desc = pango_font_description_from_string(nsoption_charp(font_fantasy));
break;
case PLOT_FONT_FAMILY_SANS_SERIF:
default:
desc = pango_font_description_from_string(nsoption_charp(font_sans));
break;
}
size = (fstyle->size * PANGO_SCALE) / FONT_SIZE_SCALE;
if (fstyle->flags & FONTF_ITALIC)
style = PANGO_STYLE_ITALIC;
else if (fstyle->flags & FONTF_OBLIQUE)
style = PANGO_STYLE_OBLIQUE;
pango_font_description_set_style(desc, style);
pango_font_description_set_weight(desc, (PangoWeight) fstyle->weight);
pango_font_description_set_size(desc, size);
if (fstyle->flags & FONTF_SMALLCAPS) {
pango_font_description_set_variant(desc,
PANGO_VARIANT_SMALL_CAPS);
} else {
pango_font_description_set_variant(desc, PANGO_VARIANT_NORMAL);
}
return desc;
}