+2007-12-10 Behdad Esfahbod <behdad@gnome.org>
+
+ Bug 478914 – Use something invalid instead of '?' when validating
+ input text
+
+ * pango/pango-layout.c (pango_layout_set_text): Set invalid input
+ bytes to -1, which gives a unichar value of -1, and eventually a
+ glyph value of -1, aka PANGO_GLYPH_INVALID_INPUT.
+
+ * pango/fonts.c (pango_font_get_glyph_extents),
+ (pango_font_get_metrics), (pango_font_get_font_map):
+ * pango/modules.c (build_map):
+ * pango/pango-context.c (get_script), (get_shaper_and_font),
+ (string_from_script), (itemize_state_process_run):
+ * pango/pango-coverage.c (pango_coverage_get):
+ * pango/pango-impl-utils.h:
+ * pango/pango-utils.c:
+ * pango/pangocairo-font.c (pango_cairo_font_get_scaled_font),
+ (_pango_cairo_font_private_get_hex_box_info),
+ (_pango_cairo_font_private_get_glyph_extents_missing):
+ * pango/pangocairo-private.h:
+ * pango/pangocairo-render.c (_pango_cairo_renderer_draw_frame),
+ (_pango_cairo_renderer_draw_box_glyph),
+ (_pango_cairo_renderer_draw_unknown_glyph):
+ * pango/pangofc-fontmap.c (pango_fc_font_map_get_patterns):
+ * pango/pangoft2-private.h:
+ * pango/pangoft2-render.c (pango_ft2_font_render_box_glyph),
+ (pango_ft2_font_render_glyph), (pango_ft2_renderer_draw_glyph):
+ * pango/pangoft2.c (pango_ft2_font_get_face),
+ (pango_ft2_font_get_glyph_extents):
+ * pango/pangox.c (pango_x_find_subfont), (pango_x_render):
+ * pango/pangoxft-font.c (_pango_xft_font_get_mini_font),
+ (get_glyph_extents_missing), (pango_xft_font_get_font):
+ * pango/pangoxft-private.h:
+ * pango/pangoxft-render.c (get_total_matrix), (draw_box),
+ (_pango_xft_renderer_draw_box_glyph),
+ (_pango_xft_renderer_draw_unknown_glyph),
+ (pango_xft_renderer_draw_glyphs):
+ * pango/shape.c (pango_shape):
+ Render PANGO_GLYPH_INVALID_INPUT to a single-width box with a cross
+ inside. Also cleanup spewed warnings and warn at the source, where
+ we fail to find a shaper, instead of at every location that we see
+ a NULL font.
+
+ * pango/pango-font.h:
+ * docs/pango-sections.txt:
+ * docs/tmpl/glyphs.sgml:
+ New public macro:
+
+ PANGO_GLYPH_INVALID_INPUT
+
2007-12-05 Behdad Esfahbod <behdad@gnome.org>
* examples/cairotwisted.c (point_on_path): Optimize double math.
pango_matrix_get_font_scale_factor
PangoGlyph
PANGO_GLYPH_EMPTY
+PANGO_GLYPH_INVALID_INPUT
PANGO_GLYPH_UNKNOWN_FLAG
PANGO_GET_UNKNOWN_GLYPH
PangoGlyphInfo
+<!-- ##### MACRO PANGO_GLYPH_INVALID_INPUT ##### -->
+<para>
+The %PANGO_GLYPH_EMPTY macro represents a #PangoGlyph value that has a
+special meaning of invalid input. #PangoLayout produces one such glyph
+per invalid input UTF-8 byte and such a glyph is rendered as a crossed
+box.
+
+Note that this value is defined such that it has the %PANGO_GLYPH_UNKNOWN_FLAG
+on.
+</para>
+
+@Since: 1.20
+
+
<!-- ##### MACRO PANGO_GLYPH_UNKNOWN_FLAG ##### -->
<para>
The %PANGO_GLYPH_UNKNOWN_FLAG macro is a flag value that can be added to
#include "pango-fontmap.h"
#include "pango-impl-utils.h"
-static const char bad_font_warning[] = "%s called with null font argument, expect ugly output";
-
struct _PangoFontDescription
{
char *family_name;
* PANGO_DESCENT(), PANGO_LBEARING(), and PANGO_RBEARING() can be used to convert
* from the extents rectangle to more traditional font metrics. The units
* of the rectangles are in 1/PANGO_SCALE of a device unit.
+ *
+ * If @font is %NULL, this function gracefully sets some sane values in the
+ * output variables and returns.
**/
void
pango_font_get_glyph_extents (PangoFont *font,
{
if (G_UNLIKELY (!font))
{
-
- if (!_pango_warning_history.get_glyph_extents)
- {
- _pango_warning_history.get_glyph_extents = TRUE;
- g_warning (bad_font_warning, "pango_font_get_glyph_extents");
- }
if (ink_rect)
{
ink_rect->x = PANGO_SCALE;
* be provided to indicate that the metrics should be retrieved that
* correspond to the script(s) used by that language.
*
+ * If @font is %NULL, this function gracefully sets some sane values in the
+ * output variables and returns.
+ *
* Return value: a #PangoFontMetrics object. The caller must call pango_font_metrics_unref()
* when finished using the object.
**/
{
if (G_UNLIKELY (!font))
{
- PangoFontMetrics *metrics;
-
- if (!_pango_warning_history.get_metrics)
- {
- _pango_warning_history.get_metrics = TRUE;
- g_warning (bad_font_warning, "pango_font_get_metrics");
- }
- metrics = pango_font_metrics_new ();
+ PangoFontMetrics *metrics = pango_font_metrics_new ();
metrics->ascent = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT;
metrics->descent = 0;
*
* Gets the font map for which the font was created.
*
- * Return value: the #PangoFontMap for the font
+ * Return value: the #PangoFontMap for the font, or %NULL if @font is %NULL.
*
* Since: 1.10
**/
pango_font_get_font_map (PangoFont *font)
{
if (G_UNLIKELY (!font))
- {
-
- if (!_pango_warning_history.get_font_map)
- {
- _pango_warning_history.get_font_map = TRUE;
- g_warning (bad_font_warning, "pango_font_get_font_map");
- }
- return NULL;
- }
+ return NULL;
if (PANGO_FONT_GET_CLASS (font)->get_font_map)
return PANGO_FONT_GET_CLASS (font)->get_font_map (font);
gchar *filename = g_build_filename (pango_get_sysconf_subdirectory (),
"pango.modules",
NULL);
- g_warning ("No builtin or dynamically\n"
- "loaded modules were found. Pango will not work correctly.\n"
- "This probably means there was an error in the creation of:\n"
- " '%s'\n"
- "You should create this file by running pango-querymodules.",
+ g_critical ("No modules found:\n"
+ "No builtin or dynamically loaded modules were found.\n"
+ "PangoFc will not work correctly.\n"
+ "This probably means there was an error in the creation of:\n"
+ " '%s'\n"
+ "You should create this file by running:\n"
+ " pango-querymodules > '%s'",
+ filename,
filename);
g_free (filename);
return state->base_font;
}
+static PangoScript
+get_script (ItemizeState *state)
+{
+ /* Always use a basic shaper for vertical layout (ie, east/west gravity)
+ * as none of our script shapers support vertical shaping right now.
+ *
+ * XXX Should move the knowledge into the shaper interface.
+ */
+
+ if (PANGO_GRAVITY_IS_VERTICAL (state->resolved_gravity))
+ return PANGO_SCRIPT_COMMON;
+ else
+ return state->script;
+}
+
static gboolean
get_shaper_and_font (ItemizeState *state,
gunichar wc,
return *shape_engine != NULL;
if (!state->exact_engines && !state->fallback_engines)
- {
- /* Always use a basic shaper for vertical layout (ie, east/west gravity)
- * as we do not support vertical shaping as of now.
- */
- PangoScript script;
-
- if (PANGO_GRAVITY_IS_VERTICAL (state->resolved_gravity))
- script = PANGO_SCRIPT_COMMON;
- else
- script = state->script;
-
- get_engines (state->context, state->derived_lang, script,
- &state->exact_engines, &state->fallback_engines);
- }
+ get_engines (state->context, state->derived_lang, get_script (state),
+ &state->exact_engines, &state->fallback_engines);
info.lang = state->derived_lang;
info.wc = wc;
}
}
+static const char *
+string_from_script (PangoScript script)
+{
+ static GEnumClass *class = NULL;
+ GEnumValue *value;
+ if (!class)
+ class = g_type_class_ref (PANGO_TYPE_SCRIPT);
+
+ value = g_enum_get_value (class, script);
+ if (!value)
+ return string_from_script (PANGO_SCRIPT_INVALID_CODE);
+
+ return value->value_nick;
+}
+
static void
itemize_state_process_run (ItemizeState *state)
{
PangoEngineShape *shape_engine;
PangoFont *font;
- if (!get_shaper_and_font (state, ' ', &shape_engine, &font))
+ if (G_UNLIKELY (!get_shaper_and_font (state, ' ', &shape_engine, &font)))
{
+ /* If no shaper was found, warn only once per fontmap/script pair */
+ PangoFontMap *fontmap = state->context->font_map;
+ const char *script_name = string_from_script (get_script (state));
+
+ if (!g_object_get_data (G_OBJECT (fontmap), script_name))
+ {
+ const char *what;
+ if (shape_engine == NULL)
+ what = "shape engine";
+ else if (font == NULL)
+ what = "font";
+ else
+ what = "nothing (oops!)";
+
+ g_warning ("failed to find shape engine, expect ugly output. engine-type='%s', script='%s'",
+ pango_font_map_get_shape_engine_type (fontmap),
+ script_name);
+
+ g_object_set_data_full (G_OBJECT (fontmap), script_name,
+ GINT_TO_POINTER (1), NULL);
+ }
+
shape_engine = _pango_get_fallback_shaper ();
font = NULL;
}
int block_index;
g_return_val_if_fail (coverage != NULL, PANGO_COVERAGE_NONE);
- g_return_val_if_fail (index >= 0, PANGO_COVERAGE_NONE);
+
+ /* index should really have been defined unsigned. Work around
+ * it by just returning NONE.
+ */
+ if (G_UNLIKELY (index < 0))
+ return PANGO_COVERAGE_NONE;
block_index = index / 256;
#endif /* PANGO_ENABLE_BACKEND */
#define PANGO_GLYPH_EMPTY ((PangoGlyph)0x0FFFFFFF)
+#define PANGO_GLYPH_INVALID_INPUT ((PangoGlyph)0xFFFFFFFF)
#define PANGO_GLYPH_UNKNOWN_FLAG ((PangoGlyph)0x10000000)
#define PANGO_GET_UNKNOWN_GLYPH(wc) ((PangoGlyph)(wc)|PANGO_GLYPH_UNKNOWN_FLAG)
parent_type, G_TYPE_FLAG_ABSTRACT)
-
-/* Warning history. Used to not spew some warnings more than once. */
-typedef struct _PangoWarningHistory PangoWarningHistory;
-
-struct _PangoWarningHistory {
- guint shape_font : 1;
- guint shape_shape_engine : 1;
- guint get_glyph_extents : 1;
- guint get_metrics : 1;
- guint get_font_map : 1;
-};
-
-extern PangoWarningHistory _pango_warning_history;
-
-
/* String interning for static strings */
#define I_(string) g_intern_static_string (string)
if (!*end)
break;
+ /* Replace invalid bytes with -1. The -1 will be converted to
+ * ((gunichar) -1) by glib, and that in turn yields a glyph value of
+ * ((PangoGlyph) -1) by PANGO_GET_UNKNOWN_GLYPH(-1),
+ * and that's PANGO_GLYPH_INVALID_INPUT.
+ */
if (!valid)
- *end++ = '?';
+ *end++ = -1;
start = end;
}
static GHashTable *pango_aliases_ht = NULL;
-PangoWarningHistory _pango_warning_history = { FALSE, FALSE, FALSE };
-
/**
* pango_version:
*
/**
* pango_quantize_line_geometry:
- * @thickness: pointer to the thickness of a line, in Pango scaled units
+ * @thickness: pointer to the thickness of a line, in Pango units
* @position: corresponding position
*
* Quantizes the thickness and position of a line, typically an
* multiples of %PANGO_SCALE. The purpose of this function is to avoid
* such lines looking blurry.
*
- * Care is taken to make sure @thickness is at least 1 when this function
- * returns, but returned @position may become zero as a result of rounding.
+ * Care is taken to make sure @thickness is at least one pixel when this
+ * function returns, but returned @position may become zero as a result
+ * of rounding.
*
* Since: 1.12
*/
#include "pangocairo-private.h"
#include "pango-impl-utils.h"
-PangoCairoWarningHistory _pango_cairo_warning_history = { FALSE };
-
#define PANGO_CAIRO_FONT_PRIVATE(font) \
((PangoCairoFontPrivate *) \
(font == NULL ? NULL : \
* The scaled font can be referenced and kept using
* cairo_scaled_font_reference().
*
- * Return value: the #cairo_scaled_font_t used by @font
+ * Return value: the #cairo_scaled_font_t used by @font,
+ * or %NULL if @font is %NULL.
*
* Since: 1.18
**/
{
PangoCairoFontPrivate *cf_priv;
- if (G_UNLIKELY (!PANGO_IS_CAIRO_FONT (cfont)))
- {
- if (!_pango_cairo_warning_history.font_get_scaled_font)
- {
- _pango_cairo_warning_history.font_get_scaled_font = TRUE;
- g_warning ("pango_cairo_font_get_scaled_font called with bad font, expect ugly output");
- }
- return NULL;
- }
+ if (G_UNLIKELY (!cfont))
+ return NULL;
cf_priv = PANGO_CAIRO_FONT_PRIVATE (cfont);
cairo_font_options_destroy (font_options);
- scaled_mini_font = pango_cairo_font_get_scaled_font (mini_font);
+ scaled_mini_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *) mini_font);
for (i = 0 ; i < 16 ; i++)
{
PangoRectangle *logical_rect)
{
PangoCairoFontHexBoxInfo *hbi;
+ gunichar ch;
gint rows, cols;
hbi = _pango_cairo_font_private_get_hex_box_info (cf_priv);
return;
}
+ ch = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
+
rows = hbi->rows;
- cols = ((glyph & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0xffff ? 6 : 4) / rows;
+ if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF))
+ cols = 1;
+ else
+ cols = ((glyph & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0xffff ? 6 : 4) / rows;
if (ink_rect)
{
const cairo_font_options_t *_pango_cairo_context_get_merged_font_options (PangoContext *context);
-typedef struct _PangoCairoWarningHistory PangoCairoWarningHistory;
-
-struct _PangoCairoWarningHistory {
- guint font_get_scaled_font : 1;
-};
-
-extern PangoCairoWarningHistory _pango_cairo_warning_history;
-
G_END_DECLS
#endif /* __PANGOCAIRO_PRIVATE_H__ */
#include <config.h>
+#include <math.h>
+
#include "pangocairo-private.h"
typedef struct _PangoCairoRendererClass PangoCairoRendererClass;
color->blue / 65535.);
}
-/* modifies cairo_set_line_width() without doing cairo_save/restore() */
+/* note: modifies crenderer->cr without doing cairo_save/restore() */
static void
_pango_cairo_renderer_draw_frame (PangoCairoRenderer *crenderer,
double x,
double y,
double width,
double height,
- double line_width)
+ double line_width,
+ gboolean invalid)
{
+ cairo_t *cr = crenderer->cr;
+
if (crenderer->do_path)
{
double d2 = line_width * .5, d = line_width;
/* we draw an outer box in one winding direction and an inner one in the
* opposite direction. This works for both cairo windings rules.
*
- * what we really want is cairo_stroke_to_path().
+ * what we really want is cairo_stroke_to_path(), but that's not
+ * implemented in cairo yet.
*/
/* outer */
- cairo_rectangle (crenderer->cr, x-d2, y-d2, width+d, height+d);
+ cairo_rectangle (cr, x-d2, y-d2, width+d, height+d);
+
/* inner */
- cairo_rectangle (crenderer->cr, x+d2 + (width-d), y+d2, - (width-d), height-d);
+ if (invalid)
+ {
+ /* delicacies of computing the joint... this is REALLY slow */
+
+ double alpha, tan_alpha2, cos_alpha;
+ double sx, sy;
+
+ alpha = atan2 (height, width);
+
+ tan_alpha2 = tan (alpha * .5);
+ if (tan_alpha2 < 1e-5 || (sx = d2 / tan_alpha2, 2. * sx > width - d))
+ sx = (width - d) * .5;
+
+ cos_alpha = cos (alpha);
+ if (cos_alpha < 1e-5 || (sy = d2 / cos_alpha, 2. * sy > height - d))
+ sy = (height - d) * .5;
+
+ /* top triangle */
+ cairo_new_sub_path (cr);
+ cairo_line_to (cr, x+width-sx, y+d2);
+ cairo_line_to (cr, x+sx, y+d2);
+ cairo_line_to (cr, x+.5*width, y+.5*height-sy);
+ cairo_close_path (cr);
+
+ /* bottom triangle */
+ cairo_new_sub_path (cr);
+ cairo_line_to (cr, x+width-sx, y+height-d2);
+ cairo_line_to (cr, x+.5*width, y+.5*height+sy);
+ cairo_line_to (cr, x+sx, y+height-d2);
+ cairo_close_path (cr);
+
+
+ alpha = G_PI_2 - alpha;
+ tan_alpha2 = tan (alpha * .5);
+ if (tan_alpha2 < 1e-5 || (sy = d2 / tan_alpha2, 2. * sy > height - d))
+ sy = (width - d) * .5;
+
+ cos_alpha = cos (alpha);
+ if (cos_alpha < 1e-5 || (sx = d2 / cos_alpha, 2. * sx > width - d))
+ sx = (width - d) * .5;
+
+ /* left triangle */
+ cairo_new_sub_path (cr);
+ cairo_line_to (cr, x+d2, y+sy);
+ cairo_line_to (cr, x+d2, y+height-sy);
+ cairo_line_to (cr, x+.5*width-sx, y+.5*height);
+ cairo_close_path (cr);
+
+ /* right triangle */
+ cairo_new_sub_path (cr);
+ cairo_line_to (cr, x+width-d2, y+sy);
+ cairo_line_to (cr, x+.5*width+sx, y+.5*height);
+ cairo_line_to (cr, x+width-d2, y+height-sy);
+ cairo_close_path (cr);
+ }
+ else
+ cairo_rectangle (cr, x+width-d2, y+d2, - (width-d), height-d);
}
else
{
- cairo_rectangle (crenderer->cr, x, y, width, height);
- cairo_set_line_width (crenderer->cr, line_width);
- cairo_stroke (crenderer->cr);
+ cairo_rectangle (cr, x, y, width, height);
+
+ if (invalid)
+ {
+ /* draw an X */
+
+ cairo_new_sub_path (cr);
+ cairo_move_to (cr, x, y);
+ cairo_rel_line_to (cr, width, height);
+
+ cairo_new_sub_path (cr);
+ cairo_move_to (cr, x + width, y);
+ cairo_rel_line_to (cr, -width, height);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+ }
+
+ cairo_set_line_width (cr, line_width);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+ cairo_set_miter_limit (cr, 2.);
+ cairo_stroke (cr);
}
}
_pango_cairo_renderer_draw_box_glyph (PangoCairoRenderer *crenderer,
PangoGlyphInfo *gi,
double cx,
- double cy)
+ double cy,
+ gboolean invalid)
{
double temp_x, temp_y;
cy + 1.5 - PANGO_UNKNOWN_GLYPH_HEIGHT,
(double)gi->geometry.width / PANGO_SCALE - 3.0,
PANGO_UNKNOWN_GLYPH_HEIGHT - 3.0,
- 1.0);
+ 1.0,
+ invalid);
cairo_move_to (crenderer->cr, temp_x, temp_y);
cairo_restore (crenderer->cr);
double temp_x, temp_y;
PangoCairoFontHexBoxInfo *hbi;
gunichar ch;
+ gboolean invalid_input;
cairo_save (crenderer->cr);
cairo_get_current_point (crenderer->cr, &temp_x, &temp_y);
- hbi = _pango_cairo_font_get_hex_box_info ((PangoCairoFont *)font);
+ ch = gi->glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
+ invalid_input = G_UNLIKELY (gi->glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF);
+ hbi = _pango_cairo_font_get_hex_box_info ((PangoCairoFont *)font);
if (!hbi || !_pango_cairo_font_install ((PangoFont *)(hbi->font), crenderer->cr))
{
- _pango_cairo_renderer_draw_box_glyph (crenderer, gi, cx, cy);
+ _pango_cairo_renderer_draw_box_glyph (crenderer, gi, cx, cy, invalid_input);
goto done;
}
- ch = gi->glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
-
rows = hbi->rows;
- cols = (ch > 0xffff ? 6 : 4) / rows;
- g_snprintf (buf, sizeof(buf), (ch > 0xffff) ? "%06X" : "%04X", ch);
+ if (G_UNLIKELY (invalid_input))
+ {
+ cols = 1;
+ }
+ else
+ {
+ cols = (ch > 0xffff ? 6 : 4) / rows;
+ g_snprintf (buf, sizeof(buf), (ch > 0xffff) ? "%06X" : "%04X", ch);
+ }
_pango_cairo_renderer_draw_frame (crenderer,
cx + hbi->pad_x * 1.5,
cy + hbi->box_descent - hbi->box_height + hbi->pad_y * 0.5,
(double)gi->geometry.width / PANGO_SCALE - 3 * hbi->pad_x,
(hbi->box_height - hbi->pad_y),
- hbi->line_width);
+ hbi->line_width,
+ invalid_input);
+
+ if (invalid_input)
+ goto done;
x0 = cx + hbi->pad_x * 3.0;
y0 = cy + hbi->box_descent - hbi->pad_y * 2;
if (!font_patterns)
{
- g_printerr ("No fonts found; this probably means that the fontconfig\n"
+ g_critical ("No fonts found:\n"
+ "This probably means that the fontconfig\n"
"library is not correctly configured. You may need to\n"
"edit the fonts.conf configuration file. More information\n"
"about fontconfig can be found in the fontconfig(3) manual\n"
- "page and on http://fontconfig.org\n");
+ "page and on http://fontconfig.org");
- /* There is no point in proceeding; we'll just get a segfault later
- * on, and a bunch more possibly confusing error messages in between.
- */
-
- /* return NULL; */
- exit (1);
+ font_patterns = FcFontSetCreate ();
}
patterns = g_slice_new (PangoFcPatternSet);
PangoRenderer *_pango_ft2_font_map_get_renderer (PangoFT2FontMap *ft2fontmap);
-typedef struct _PangoFT2WarningHistory PangoFT2WarningHistory;
-
-struct _PangoFT2WarningHistory {
- guint get_face : 1;
-};
-
-extern PangoFT2WarningHistory _pango_ft2_warning_history;
-
#endif /* __PANGOFT2_PRIVATE_H__ */
}
static PangoFT2RenderedGlyph *
-pango_ft2_font_render_box_glyph (int width,
- int height,
- int top)
+pango_ft2_font_render_box_glyph (int width,
+ int height,
+ int top,
+ gboolean invalid)
{
PangoFT2RenderedGlyph *box;
int i, j, offset1, offset2, line_width;
}
}
+ if (invalid)
+ {
+ /* XXX This may scrabble memory. Didn't check close enough */
+ int inc = PANGO_SCALE * MAX (width - line_width, 0) / (height + 1);
+ offset1 = PANGO_SCALE;
+ offset2 = PANGO_SCALE * MAX (width - line_width - 1, 0) ;
+ for (i = box->bitmap.pitch;
+ i < (box->bitmap.rows - 1) * box->bitmap.pitch;
+ i += box->bitmap.pitch)
+ {
+ for (j = 0; j < line_width; j++)
+ {
+ box->bitmap.buffer[PANGO_PIXELS (offset1) + i + j] = 0xff;
+ box->bitmap.buffer[PANGO_PIXELS (offset2) + i + j] = 0xff;
+ }
+ offset1 += inc;
+ offset2 -= inc;
+ }
+
+ }
+
return box;
}
static PangoFT2RenderedGlyph *
pango_ft2_font_render_glyph (PangoFont *font,
- int glyph_index)
+ PangoGlyph glyph_index)
{
FT_Face face;
+ gboolean invalid_input;
+
+ invalid_input = glyph_index == PANGO_GLYPH_INVALID_INPUT || (glyph_index & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0x10FFFF;
if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG)
{
box = pango_ft2_font_render_box_glyph (PANGO_PIXELS (metrics->approximate_char_width),
PANGO_PIXELS (metrics->ascent + metrics->descent),
- PANGO_PIXELS (metrics->ascent));
+ PANGO_PIXELS (metrics->ascent),
+ invalid_input);
pango_font_metrics_unref (metrics);
return box;
generic_box:
return pango_ft2_font_render_box_glyph (PANGO_UNKNOWN_GLYPH_WIDTH,
PANGO_UNKNOWN_GLYPH_HEIGHT,
- PANGO_UNKNOWN_GLYPH_HEIGHT);
+ PANGO_UNKNOWN_GLYPH_HEIGHT,
+ invalid_input);
}
}
if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
{
- glyph = pango_ft2_get_unknown_glyph (font);
- if (glyph == PANGO_GLYPH_EMPTY)
- {
- /* No unknown glyph found for the font, draw a box */
+ /* Since we don't draw hexbox for FT2 renderer,
+ * unifiy the rendered bitmap in the cache by converting
+ * all missing glyphs to either INVALID_INPUT or UNKNOWN_FLAG.
+ */
- /* Since we only draw an empty box for FT2 renderer,
- * we unify the rendered bitmaps in the cache.
- */
- glyph = PANGO_GLYPH_UNKNOWN_FLAG;
- }
+ gunichar wc = glyph & (~PANGO_GLYPH_UNKNOWN_FLAG);
+
+ if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || wc > 0x10FFFF))
+ glyph = PANGO_GLYPH_INVALID_INPUT;
+ else
+ glyph = PANGO_GLYPH_UNKNOWN_FLAG;
}
rendered_glyph = _pango_ft2_font_get_cache_glyph_data (font, glyph);
#include "pangofc-fontmap.h"
#include "pangofc-private.h"
-PangoFT2WarningHistory _pango_ft2_warning_history = { FALSE };
-
/* for compatibility with older freetype versions */
#ifndef FT_LOAD_TARGET_MONO
#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
* face from pango_fc_font_lock_face() you must call
* pango_fc_font_unlock_face().
*
- * Return value: a pointer to a <type>FT_Face</type> structure, with the size set correctly
+ * Return value: a pointer to a <type>FT_Face</type> structure, with the size set correctly,
+ * or %NULL if @font is %NULL.
**/
FT_Face
pango_ft2_font_get_face (PangoFont *font)
int hintstyle;
int id;
- if (G_UNLIKELY (!PANGO_FT2_IS_FONT (font)))
- {
- if (!_pango_ft2_warning_history.get_face)
- {
- _pango_ft2_warning_history.get_face = TRUE;
- g_warning ("pango_ft2_font_get_face called with bad font, expect ugly output");
- }
- return NULL;
- }
+ if (G_UNLIKELY (!font))
+ return NULL;
pattern = fcfont->font_pattern;
if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
{
- glyph = pango_ft2_get_unknown_glyph (font);
- if (glyph == PANGO_GLYPH_EMPTY)
- {
- /* No unknown glyph found for the font, draw a box */
- PangoFontMetrics *metrics = pango_font_get_metrics (font, NULL);
+ PangoFontMetrics *metrics = pango_font_get_metrics (font, NULL);
- if (metrics)
+ if (metrics)
+ {
+ if (ink_rect)
{
- if (ink_rect)
- {
- ink_rect->x = PANGO_SCALE;
- ink_rect->width = metrics->approximate_char_width - 2 * PANGO_SCALE;
- ink_rect->y = - (metrics->ascent - PANGO_SCALE);
- ink_rect->height = metrics->ascent + metrics->descent - 2 * PANGO_SCALE;
- }
- if (logical_rect)
- {
- logical_rect->x = 0;
- logical_rect->width = metrics->approximate_char_width;
- logical_rect->y = -metrics->ascent;
- logical_rect->height = metrics->ascent + metrics->descent;
- }
-
- pango_font_metrics_unref (metrics);
+ ink_rect->x = PANGO_SCALE;
+ ink_rect->width = metrics->approximate_char_width - 2 * PANGO_SCALE;
+ ink_rect->y = - (metrics->ascent - PANGO_SCALE);
+ ink_rect->height = metrics->ascent + metrics->descent - 2 * PANGO_SCALE;
}
- else
+ if (logical_rect)
{
- if (ink_rect)
- ink_rect->x = ink_rect->y = ink_rect->height = ink_rect->width = 0;
- if (logical_rect)
- logical_rect->x = logical_rect->y = logical_rect->height = logical_rect->width = 0;
+ logical_rect->x = 0;
+ logical_rect->width = metrics->approximate_char_width;
+ logical_rect->y = -metrics->ascent;
+ logical_rect->height = metrics->ascent + metrics->descent;
}
- return;
+
+ pango_font_metrics_unref (metrics);
+ }
+ else
+ {
+ if (ink_rect)
+ ink_rect->x = ink_rect->y = ink_rect->height = ink_rect->width = 0;
+ if (logical_rect)
+ logical_rect->x = logical_rect->y = logical_rect->height = logical_rect->width = 0;
}
+ return;
}
info = pango_ft2_font_get_glyph_info (font, glyph, TRUE);
PangoXFont *xfont = (PangoXFont *)font;
if (subfont_index < 1 || subfont_index > xfont->n_subfonts)
- {
- g_warning ("Invalid subfont %d", subfont_index);
- return NULL;
- }
+ return NULL;
return xfont->subfonts[subfont_index-1];
}
glyph_y >= -16384 && glyph_y <= 32767))
goto next_glyph;
- if ((glyph & PANGO_GLYPH_UNKNOWN_FLAG) == 0)
+ if (G_LIKELY ((glyph & PANGO_GLYPH_UNKNOWN_FLAG) == 0))
{
guint16 index = PANGO_X_GLYPH_INDEX (glyph);
guint16 subfont_index = PANGO_X_GLYPH_SUBFONT (glyph);
int baseline;
int stroke_thick;
gunichar wc;
+ gboolean invalid_input;
unknown_glyph:
FLUSH;
x2 = x1 + PANGO_PIXELS (glyphs->glyphs[i].geometry.width);
baseline = glyph_y;
- stroke_thick = MAX ((int) (0.5 + 0.075 * (y2 - y1)), 1);
+ stroke_thick = MAX ((int) (0.5 + 0.025 * (y2 - y1)), 1);
if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
- wc = glyph & (~PANGO_GLYPH_UNKNOWN_FLAG);
+ wc = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
else
wc = 0;
+ invalid_input = glyph == PANGO_GLYPH_INVALID_INPUT || wc > 0x10FFFF;
switch (wc)
{
default:
{
/* Perhaps we should draw the box-with-numbers as in the
- * Xft backend, though we have no guarantee of having
+ * other backends, though we have no guarantee of having
* an appropriate size of font. Right now, we just
* draw an empty box. (To draw the box-with-numbers.
* the backends would have to be changed to use
XFillRectangle (display, d, gc,
x1, y2 - stroke_thick,
x2 - x1, stroke_thick);
+ if (invalid_input)
+ {
+ XDrawLine (display, d, gc,
+ x1, y1,
+ x2-1, y2-1);
+ XDrawLine (display, d, gc,
+ x2-1, y1,
+ x1, y2-1);
+ }
break;
}
#include "pangoxft-private.h"
#include "pangofc-private.h"
-PangoXftWarningHistory _pango_xft_warning_history = { FALSE };
-
#define PANGO_XFT_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_XFT_FONT, PangoXftFontClass))
#define PANGO_XFT_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_XFT_FONT))
#define PANGO_XFT_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_XFT_FONT, PangoXftFontClass))
pango_font_description_set_size (desc, new_size);
xfont->mini_font = pango_font_map_load_font (fcfont->fontmap, context, desc);
- if (!xfont->mini_font)
- return NULL;
-
pango_font_description_free (desc);
g_object_unref (context);
+ if (!xfont->mini_font)
+ return NULL;
+
mini_xft = xft_font_get_font (xfont->mini_font);
for (i = 0 ; i < 16 ; i++)
height = MAX (height, extents.height);
}
-
xfont->mini_width = PANGO_SCALE * width;
xfont->mini_height = PANGO_SCALE * height;
xfont->mini_pad = PANGO_SCALE * MIN (height / 2, MAX ((int)(2.2 * height + 27) / 28, 1));
{
PangoFont *font = PANGO_FONT (xfont);
XftFont *xft_font = xft_font_get_font (font);
+ gunichar ch;
+ gint cols;
+
+ ch = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
- gint cols = (glyph & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0xffff ? 3 : 2;
+ if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF))
+ cols = 1;
+ else
+ cols = ch > 0xffff ? 3 : 2;
_pango_xft_font_get_mini_font (xfont);
*
* Returns the XftFont of a font.
*
- * Return value: the XftFont associated to @font.
+ * Return value: the XftFont associated to @font, or %NULL if @font is %NULL.
**/
XftFont *
pango_xft_font_get_font (PangoFont *font)
{
- if (G_UNLIKELY (!PANGO_XFT_IS_FONT (font)))
- {
- if (!_pango_xft_warning_history.get_font)
- {
- _pango_xft_warning_history.get_font = TRUE;
- g_warning ("pango_xft_font_get_font called with bad font, expect ugly output");
- }
- return NULL;
- }
+ if (G_UNLIKELY (!font))
+ return NULL;
return xft_font_get_font (font);
}
XftFont *xft_font; /* created on demand */
PangoFont *mini_font; /* font used to display missing glyphs */
- guint16 mini_width; /* metrics for missing glyph drawing */
- guint16 mini_height;
- guint16 mini_pad;
+ guint mini_width; /* metrics for missing glyph drawing */
+ guint mini_height;
+ guint mini_pad;
GHashTable *glyph_info; /* Used only when we can't get
* glyph extents out of Xft because
PangoFont *_pango_xft_font_get_mini_font (PangoXftFont *xfont);
-typedef struct _PangoXftWarningHistory PangoXftWarningHistory;
-
-struct _PangoXftWarningHistory {
- guint get_font : 1;
-};
-
-extern PangoXftWarningHistory _pango_xft_warning_history;
-
G_END_DECLS
#endif /* __PANGOXFT_PRIVATE_H__ */
}
static void
+get_total_matrix (PangoMatrix *total,
+ const PangoMatrix *global,
+ double x,
+ double y,
+ double width,
+ double height)
+{
+ PangoMatrix local = PANGO_MATRIX_INIT;
+ gdouble angle = atan2 (height, width);
+
+ pango_matrix_translate (&local, x, y);
+ pango_matrix_rotate (&local, -angle * (180. / G_PI));
+
+ *total = *global;
+ pango_matrix_concat (total, &local);
+}
+
+static void
draw_box (PangoRenderer *renderer,
gint line_width,
gint x,
gint y,
gint width,
- gint height)
+ gint height,
+ gboolean invalid)
{
pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
x, y, width, line_width);
x + width - line_width, y + line_width, line_width, height - line_width * 2);
pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
x, y + height - line_width, width, line_width);
+
+ if (invalid)
+ {
+ int length;
+ double in_width, in_height;
+ PangoMatrix orig_matrix = PANGO_MATRIX_INIT, new_matrix;
+ const PangoMatrix *porig_matrix;
+
+ in_width = pango_units_to_double (width - 2 * line_width);
+ in_height = pango_units_to_double (height - 2 * line_width);
+ length = PANGO_SCALE * sqrt (in_width*in_width + in_height*in_height);
+
+ porig_matrix = pango_renderer_get_matrix (renderer);
+ if (porig_matrix)
+ {
+ orig_matrix = *porig_matrix;
+ porig_matrix = &orig_matrix;
+ }
+
+ get_total_matrix (&new_matrix, &orig_matrix,
+ pango_units_to_double (x + line_width), pango_units_to_double (y + line_width),
+ in_width, in_height);
+ pango_renderer_set_matrix (renderer, &new_matrix);
+ pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
+ 0, -line_width / 2, length, line_width);
+
+ get_total_matrix (&new_matrix, &orig_matrix,
+ pango_units_to_double (x + line_width), pango_units_to_double (y + height - line_width),
+ in_width, -in_height);
+ pango_renderer_set_matrix (renderer, &new_matrix);
+ pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
+ 0, -line_width / 2, length, line_width);
+
+ pango_renderer_set_matrix (renderer, porig_matrix);
+ }
}
static void
_pango_xft_renderer_draw_box_glyph (PangoRenderer *renderer,
PangoGlyphInfo *gi,
int glyph_x,
- int glyph_y)
+ int glyph_y,
+ gboolean invalid)
{
int x = glyph_x + PANGO_SCALE;
int y = glyph_y - PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT - 1);
int height = PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT - 2);
if (box_in_bounds (renderer, x, y, width, height))
- draw_box (renderer, PANGO_SCALE, x, y, width, height);
+ draw_box (renderer, PANGO_SCALE, x, y, width, height, invalid);
}
static void
int xs[4];
int row, col;
int cols;
- PangoGlyph glyph;
+ gunichar ch;
+ gboolean invalid_input;
+
+ PangoFont *mini_font;
+ XftFont *mini_xft_font;
- PangoFont *mini_font = _pango_xft_font_get_mini_font (xfont);
- XftFont *mini_xft_font = pango_xft_font_get_font (mini_font);
+ ch = gi->glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
+ if (G_UNLIKELY (gi->glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF))
+ {
+ invalid_input = TRUE;
+ cols = 1;
+ }
+ else
+ {
+ invalid_input = FALSE;
+ cols = ch > 0xffff ? 3 : 2;
+ g_snprintf (buf, sizeof(buf), (ch > 0xffff) ? "%06X" : "%04X", ch);
+ }
+
+ mini_font = _pango_xft_font_get_mini_font (xfont);
+ mini_xft_font = pango_xft_font_get_font (mini_font);
if (!mini_xft_font)
{
- _pango_xft_renderer_draw_box_glyph (renderer, gi, glyph_x, glyph_y);
+ _pango_xft_renderer_draw_box_glyph (renderer, gi, glyph_x, glyph_y, invalid_input);
return;
}
- glyph = gi->glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
ys[0] = glyph_y - PANGO_SCALE * xft_font->ascent + PANGO_SCALE * (((xft_font->ascent + xft_font->descent) - (xfont->mini_height * 2 + xfont->mini_pad * 5 + PANGO_SCALE / 2) / PANGO_SCALE) / 2);
ys[1] = ys[0] + 2 * xfont->mini_pad + xfont->mini_height;
xs[2] = xs[1] + xfont->mini_width + xfont->mini_pad;
xs[3] = xs[2] + xfont->mini_width + xfont->mini_pad;
- if (glyph > 0xffff)
- {
- cols = 3;
- g_snprintf (buf, sizeof(buf), "%06X", glyph);
- }
- else
- {
- cols = 2;
- g_snprintf (buf, sizeof(buf), "%04X", glyph);
- }
-
if (box_in_bounds (renderer,
xs[0], ys[0],
xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1),
draw_box (renderer, xfont->mini_pad,
xs[0], ys[0],
xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1),
- xfont->mini_height * 2 + xfont->mini_pad * 5);
+ xfont->mini_height * 2 + xfont->mini_pad * 5,
+ invalid_input);
+
+ if (invalid_input)
+ return;
for (row = 0; row < 2; row++)
for (col = 0; col < cols; col++)
int glyph_x = x + x_off + gi->geometry.x_offset;
int glyph_y = y + gi->geometry.y_offset;
- _pango_xft_renderer_draw_box_glyph (renderer, gi, glyph_x, glyph_y);
+ _pango_xft_renderer_draw_unknown_glyph (renderer,
+ xfont,
+ xft_font,
+ gi,
+ glyph_x,
+ glyph_y);
}
x_off += gi->geometry.width;
glyphs->num_glyphs = 0;
- if (G_LIKELY (PANGO_IS_ENGINE_SHAPE (analysis->shape_engine) && PANGO_IS_FONT (analysis->font)))
+ if (G_LIKELY (analysis->shape_engine && analysis->font))
{
_pango_engine_shape_shape (analysis->shape_engine, analysis->font,
text, length, analysis, glyphs);
}
}
else
- {
- if (!PANGO_IS_ENGINE_SHAPE (analysis->shape_engine) &&
- !_pango_warning_history.shape_shape_engine)
- {
- _pango_warning_history.shape_shape_engine = TRUE;
- g_warning ("pango_shape called with bad shape_engine, expect ugly output");
- }
- if (!PANGO_IS_FONT (analysis->font) &&
- !_pango_warning_history.shape_font)
- {
- _pango_warning_history.shape_font = TRUE;
- g_warning ("pango_shape called with bad font, expect ugly output");
- }
-
- glyphs->num_glyphs = 0;
- }
+ glyphs->num_glyphs = 0;
if (!glyphs->num_glyphs)
{