1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 2008-2010 gEDA Contributors (see ChangeLog for details)
4 * Copyright (C) 2000 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * This file based on GDK's gdkpango.c (LGPL V2+)
22 * Copyright (C) 2000 Red Hat, Inc.
30 #include <pango/pangocairo.h>
31 #include <gschem_pango.h>
33 #define MAGIC_OVERBAR_POS_CONSTANT 0.8
35 struct _GschemPangoRendererPrivate
37 cairo_surface_t
*surface
;
39 /* GschemPangoRenderer specific state */
45 static PangoAttrType gschem_pango_attr_overbar_type
;
52 G_DEFINE_TYPE (GschemPangoRenderer
, gschem_pango_renderer
, PANGO_TYPE_RENDERER
)
55 gschem_pango_renderer_finalize (GObject
*object
)
57 G_OBJECT_CLASS (gschem_pango_renderer_parent_class
)->finalize (object
);
61 gschem_pango_renderer_constructor (GType type
,
62 guint n_construct_properties
,
63 GObjectConstructParam
*construct_params
)
66 GschemPangoRenderer
*gschem_renderer
;
68 object
= G_OBJECT_CLASS (gschem_pango_renderer_parent_class
)->constructor (type
,
69 n_construct_properties
,
72 gschem_renderer
= GSCHEM_PANGO_RENDERER (object
);
74 if (gschem_renderer
->priv
->cr
== NULL
) {
75 g_warning ("Cairo context must be specified at construct time for GschemPangoRenderer");
82 get_cairo_context (GschemPangoRenderer
*gschem_renderer
,
85 GschemPangoRendererPrivate
*priv
= gschem_renderer
->priv
;
91 gschem_pango_renderer_draw_glyphs (PangoRenderer
*renderer
,
93 PangoGlyphString
*glyphs
,
97 GschemPangoRenderer
*gschem_renderer
= GSCHEM_PANGO_RENDERER (renderer
);
98 GschemPangoRendererPrivate
*priv
= gschem_renderer
->priv
;
101 cr
= get_cairo_context (gschem_renderer
,
102 PANGO_RENDER_PART_FOREGROUND
);
106 double rx
, ry
, rwidth
, rheight
, cheight
;
107 PangoFontMetrics
*metrics
;
108 PangoRectangle logical
;
109 int underline_thickness
;
111 /* Make the thickness the same as for the font's underline */
112 metrics
= pango_font_get_metrics (font
, NULL
);
113 underline_thickness
= pango_font_metrics_get_underline_thickness (metrics
);
114 pango_font_metrics_unref (metrics
);
116 pango_glyph_string_extents (glyphs
, font
, NULL
, &logical
);
119 ry
= y
- logical
.height
* MAGIC_OVERBAR_POS_CONSTANT
;
120 rwidth
= logical
.width
;
121 rheight
= underline_thickness
;
123 cheight
= rheight
/ PANGO_SCALE
;
125 /* Allow the overbar to fade out as it becomes < 1px high */
127 cheight
= (int)(cheight
);
129 /* \note The +1 on width is a hack to ensure hinting doesn't
130 * sometimes cause the overbars to be broken by a 1px gap
131 * if the overbar spans multiple calls to this function.
134 (int)(rx
/ PANGO_SCALE
), (int)(ry
/ PANGO_SCALE
),
135 (int)(rwidth
/ PANGO_SCALE
) + 1, cheight
);
139 cairo_move_to (cr
, (double)x
/ PANGO_SCALE
, (double)y
/ PANGO_SCALE
);
140 pango_cairo_show_glyph_string (cr
, font
, glyphs
);
144 gschem_pango_renderer_draw_rectangle (PangoRenderer
*renderer
,
145 PangoRenderPart part
,
151 GschemPangoRenderer
*gschem_renderer
= GSCHEM_PANGO_RENDERER (renderer
);
154 cr
= get_cairo_context (gschem_renderer
, part
);
157 (double)x
/ PANGO_SCALE
, (double)y
/ PANGO_SCALE
,
158 (double)width
/ PANGO_SCALE
, (double)height
/ PANGO_SCALE
);
163 gschem_pango_renderer_draw_error_underline (PangoRenderer
*renderer
,
169 GschemPangoRenderer
*gschem_renderer
= GSCHEM_PANGO_RENDERER (renderer
);
172 cr
= get_cairo_context (gschem_renderer
, PANGO_RENDER_PART_UNDERLINE
);
174 pango_cairo_show_error_underline (cr
,
175 (double)x
/ PANGO_SCALE
, (double)y
/ PANGO_SCALE
,
176 (double)width
/ PANGO_SCALE
, (double)height
/ PANGO_SCALE
);
180 gschem_pango_renderer_part_changed (PangoRenderer
*renderer
,
181 PangoRenderPart part
)
186 gschem_pango_renderer_begin (PangoRenderer
*renderer
)
191 gschem_pango_renderer_end (PangoRenderer
*renderer
)
196 gschem_pango_renderer_prepare_run (PangoRenderer
*renderer
,
199 GschemPangoRenderer
*gschem_renderer
= GSCHEM_PANGO_RENDERER (renderer
);
200 gboolean overbar
= FALSE
;
201 gboolean changed
= FALSE
;
204 for (l
= run
->item
->analysis
.extra_attrs
; l
; l
= l
->next
) {
205 PangoAttribute
*attr
= l
->data
;
207 /* overbar_type isn't necessarily initialized, but it is 0,
208 * which is an invalid type so won't occur.
210 if (attr
->klass
->type
== gschem_pango_attr_overbar_type
) {
211 overbar
= ((GschemPangoAttrOverbar
*)attr
)->overbar
;
215 if (overbar
!= gschem_renderer
->priv
->overbar
) {
216 gschem_renderer
->priv
->overbar
= overbar
;
221 pango_renderer_part_changed (renderer
, PANGO_RENDER_PART_FOREGROUND
);
223 PANGO_RENDERER_CLASS (gschem_pango_renderer_parent_class
)->prepare_run (renderer
, run
);
227 gschem_pango_renderer_set_property (GObject
*object
, guint prop_id
,
228 const GValue
*value
, GParamSpec
*pspec
)
230 GschemPangoRenderer
*gschem_renderer
= GSCHEM_PANGO_RENDERER (object
);
234 gschem_renderer
->priv
->cr
= g_value_get_pointer (value
);
237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
243 gschem_pango_renderer_get_property (GObject
*object
, guint prop_id
,
244 GValue
*value
, GParamSpec
*pspec
)
246 GschemPangoRenderer
*gschem_renderer
= GSCHEM_PANGO_RENDERER (object
);
250 g_value_set_pointer (value
, gschem_renderer
->priv
->cr
);
253 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
259 gschem_pango_renderer_init (GschemPangoRenderer
*renderer
)
261 renderer
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (renderer
,
262 GSCHEM_TYPE_PANGO_RENDERER
,
263 GschemPangoRendererPrivate
);
267 gschem_pango_renderer_class_init (GschemPangoRendererClass
*klass
)
269 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
271 PangoRendererClass
*renderer_class
= PANGO_RENDERER_CLASS (klass
);
273 renderer_class
->draw_glyphs
= gschem_pango_renderer_draw_glyphs
;
274 renderer_class
->draw_rectangle
= gschem_pango_renderer_draw_rectangle
;
275 renderer_class
->draw_error_underline
= gschem_pango_renderer_draw_error_underline
;
276 renderer_class
->part_changed
= gschem_pango_renderer_part_changed
;
277 renderer_class
->begin
= gschem_pango_renderer_begin
;
278 renderer_class
->end
= gschem_pango_renderer_end
;
279 renderer_class
->prepare_run
= gschem_pango_renderer_prepare_run
;
281 object_class
->finalize
= gschem_pango_renderer_finalize
;
282 object_class
->constructor
= gschem_pango_renderer_constructor
;
283 object_class
->set_property
= gschem_pango_renderer_set_property
;
284 object_class
->get_property
= gschem_pango_renderer_get_property
;
286 g_object_class_install_property (object_class
,
288 g_param_spec_pointer ("cr",
290 _("the cairo context for the renderer"),
291 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
292 G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
|
293 G_PARAM_STATIC_BLURB
));
295 g_type_class_add_private (object_class
, sizeof (GschemPangoRendererPrivate
));
299 * \brief Create a new PangoRenderer
301 * Create a new #PangoRenderer. Normally you can use the results
302 * of gschem_pango_renderer_get_default() rather than creating a new renderer.
304 * \param [in] cr a cairo renderer
305 * \return a newly created #PangoRenderer. Free with g_object_unref().
308 gschem_pango_renderer_new (cairo_t
*cr
)
310 return g_object_new (GSCHEM_TYPE_PANGO_RENDERER
, "cr", cr
, NULL
);
314 gschem_pango_show_layout (cairo_t
*cr
,
317 static PangoRenderer
*renderer
= NULL
;
318 static cairo_t
*cr_cache
= NULL
;
321 if (cr_cache
!= cr
&& renderer
!= NULL
) {
322 g_object_unref (renderer
);
326 if (renderer
== NULL
) {
327 renderer
= gschem_pango_renderer_new (cr
);
331 cairo_get_current_point (cr
, &x_off
, &y_off
);
333 pango_renderer_draw_layout (renderer
, pl
, x_off
* PANGO_SCALE
, y_off
* PANGO_SCALE
);
337 /* GschemPangoAttrOverbar */
339 static PangoAttribute
*
340 gschem_pango_attr_overbar_copy (const PangoAttribute
*attr
)
342 const GschemPangoAttrOverbar
*e
= (const GschemPangoAttrOverbar
*) attr
;
344 return gschem_pango_attr_overbar_new (e
->overbar
);
348 gschem_pango_attr_overbar_destroy (PangoAttribute
*attr
)
354 gschem_pango_attr_overbar_compare (const PangoAttribute
*attr1
,
355 const PangoAttribute
*attr2
)
357 const GschemPangoAttrOverbar
*e1
= (const GschemPangoAttrOverbar
*) attr1
;
358 const GschemPangoAttrOverbar
*e2
= (const GschemPangoAttrOverbar
*) attr2
;
360 return e1
->overbar
== e2
->overbar
;
364 * Creates a new attribute flagging a region as being drawn with overbar or not
366 * \param [in] overbar if the region should be drawn with an overbar
367 * \return a new #PangoAttribute
370 gschem_pango_attr_overbar_new (gboolean overbar
)
372 GschemPangoAttrOverbar
*result
;
374 static PangoAttrClass klass
= { 0,
375 gschem_pango_attr_overbar_copy
,
376 gschem_pango_attr_overbar_destroy
,
377 gschem_pango_attr_overbar_compare
};
380 klass
.type
= gschem_pango_attr_overbar_type
=
381 pango_attr_type_register ("GschemPangoAttrOverbar");
383 result
= g_new (GschemPangoAttrOverbar
, 1);
384 result
->attr
.klass
= &klass
;
385 result
->overbar
= overbar
;
387 return (PangoAttribute
*)result
;