gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 2008-2010 gEDA Contributors (see ChangeLog for details) 00004 * Copyright (C) 2000 Red Hat, Inc. 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public 00017 * License along with this library; if not, write to the 00018 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301 USA 00020 * 00021 * This file based on GDK's gdkpango.c (LGPL V2+) 00022 * Copyright (C) 2000 Red Hat, Inc. 00023 */ 00024 00025 #include <config.h> 00026 00027 #include "gschem.h" 00028 00029 #include <math.h> 00030 #include <pango/pangocairo.h> 00031 #include <gschem_pango.h> 00032 00033 #define MAGIC_OVERBAR_POS_CONSTANT 0.8 00034 00035 struct _GschemPangoRendererPrivate 00036 { 00037 cairo_surface_t *surface; 00038 00039 /* GschemPangoRenderer specific state */ 00040 gboolean overbar; 00041 00042 cairo_t *cr; 00043 }; 00044 00045 static PangoAttrType gschem_pango_attr_overbar_type; 00046 00047 enum { 00048 PROP_0, 00049 PROP_CR 00050 }; 00051 00052 G_DEFINE_TYPE (GschemPangoRenderer, gschem_pango_renderer, PANGO_TYPE_RENDERER) 00053 00054 static void 00055 gschem_pango_renderer_finalize (GObject *object) 00056 { 00057 G_OBJECT_CLASS (gschem_pango_renderer_parent_class)->finalize (object); 00058 } 00059 00060 static GObject* 00061 gschem_pango_renderer_constructor (GType type, 00062 guint n_construct_properties, 00063 GObjectConstructParam *construct_params) 00064 { 00065 GObject *object; 00066 GschemPangoRenderer *gschem_renderer; 00067 00068 object = G_OBJECT_CLASS (gschem_pango_renderer_parent_class)->constructor (type, 00069 n_construct_properties, 00070 construct_params); 00071 00072 gschem_renderer = GSCHEM_PANGO_RENDERER (object); 00073 00074 if (gschem_renderer->priv->cr == NULL) { 00075 g_warning ("Cairo context must be specified at construct time for GschemPangoRenderer"); 00076 } 00077 00078 return object; 00079 } 00080 00081 static cairo_t * 00082 get_cairo_context (GschemPangoRenderer *gschem_renderer, 00083 PangoRenderPart part) 00084 { 00085 GschemPangoRendererPrivate *priv = gschem_renderer->priv; 00086 00087 return priv->cr; 00088 } 00089 00090 static void 00091 gschem_pango_renderer_draw_glyphs (PangoRenderer *renderer, 00092 PangoFont *font, 00093 PangoGlyphString *glyphs, 00094 int x, 00095 int y) 00096 { 00097 GschemPangoRenderer *gschem_renderer = GSCHEM_PANGO_RENDERER (renderer); 00098 GschemPangoRendererPrivate *priv = gschem_renderer->priv; 00099 cairo_t *cr; 00100 00101 cr = get_cairo_context (gschem_renderer, 00102 PANGO_RENDER_PART_FOREGROUND); 00103 00104 00105 if (priv->overbar) { 00106 double rx, ry, rwidth, rheight, cheight; 00107 PangoFontMetrics *metrics; 00108 PangoRectangle logical; 00109 int underline_thickness; 00110 00111 /* Make the thickness the same as for the font's underline */ 00112 metrics = pango_font_get_metrics (font, NULL); 00113 underline_thickness = pango_font_metrics_get_underline_thickness (metrics); 00114 pango_font_metrics_unref (metrics); 00115 00116 pango_glyph_string_extents (glyphs, font, NULL, &logical); 00117 00118 rx = x; 00119 ry = y - logical.height * MAGIC_OVERBAR_POS_CONSTANT; 00120 rwidth = logical.width; 00121 rheight = underline_thickness; 00122 00123 cheight = rheight / PANGO_SCALE; 00124 00125 /* Allow the overbar to fade out as it becomes < 1px high */ 00126 if (cheight > 1.0) 00127 cheight = (int)(cheight); 00128 00129 /* \note The +1 on width is a hack to ensure hinting doesn't 00130 * sometimes cause the overbars to be broken by a 1px gap 00131 * if the overbar spans multiple calls to this function. 00132 */ 00133 cairo_rectangle (cr, 00134 (int)(rx / PANGO_SCALE), (int)(ry / PANGO_SCALE), 00135 (int)(rwidth / PANGO_SCALE) + 1, cheight); 00136 cairo_fill (cr); 00137 } 00138 00139 cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE); 00140 pango_cairo_show_glyph_string (cr, font, glyphs); 00141 } 00142 00143 static void 00144 gschem_pango_renderer_draw_rectangle (PangoRenderer *renderer, 00145 PangoRenderPart part, 00146 int x, 00147 int y, 00148 int width, 00149 int height) 00150 { 00151 GschemPangoRenderer *gschem_renderer = GSCHEM_PANGO_RENDERER (renderer); 00152 cairo_t *cr; 00153 00154 cr = get_cairo_context (gschem_renderer, part); 00155 00156 cairo_rectangle (cr, 00157 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE, 00158 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE); 00159 cairo_fill (cr); 00160 } 00161 00162 static void 00163 gschem_pango_renderer_draw_error_underline (PangoRenderer *renderer, 00164 int x, 00165 int y, 00166 int width, 00167 int height) 00168 { 00169 GschemPangoRenderer *gschem_renderer = GSCHEM_PANGO_RENDERER (renderer); 00170 cairo_t *cr; 00171 00172 cr = get_cairo_context (gschem_renderer, PANGO_RENDER_PART_UNDERLINE); 00173 00174 pango_cairo_show_error_underline (cr, 00175 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE, 00176 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE); 00177 } 00178 00179 static void 00180 gschem_pango_renderer_part_changed (PangoRenderer *renderer, 00181 PangoRenderPart part) 00182 { 00183 } 00184 00185 static void 00186 gschem_pango_renderer_begin (PangoRenderer *renderer) 00187 { 00188 } 00189 00190 static void 00191 gschem_pango_renderer_end (PangoRenderer *renderer) 00192 { 00193 } 00194 00195 static void 00196 gschem_pango_renderer_prepare_run (PangoRenderer *renderer, 00197 PangoLayoutRun *run) 00198 { 00199 GschemPangoRenderer *gschem_renderer = GSCHEM_PANGO_RENDERER (renderer); 00200 gboolean overbar = FALSE; 00201 gboolean changed = FALSE; 00202 GSList *l; 00203 00204 for (l = run->item->analysis.extra_attrs; l; l = l->next) { 00205 PangoAttribute *attr = l->data; 00206 00207 /* overbar_type isn't necessarily initialized, but it is 0, 00208 * which is an invalid type so won't occur. 00209 */ 00210 if (attr->klass->type == gschem_pango_attr_overbar_type) { 00211 overbar = ((GschemPangoAttrOverbar*)attr)->overbar; 00212 } 00213 } 00214 00215 if (overbar != gschem_renderer->priv->overbar) { 00216 gschem_renderer->priv->overbar = overbar; 00217 changed = TRUE; 00218 } 00219 00220 if (changed) 00221 pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND); 00222 00223 PANGO_RENDERER_CLASS (gschem_pango_renderer_parent_class)->prepare_run (renderer, run); 00224 } 00225 00226 static void 00227 gschem_pango_renderer_set_property (GObject *object, guint prop_id, 00228 const GValue *value, GParamSpec *pspec) 00229 { 00230 GschemPangoRenderer *gschem_renderer = GSCHEM_PANGO_RENDERER (object); 00231 00232 switch (prop_id) { 00233 case PROP_CR: 00234 gschem_renderer->priv->cr = g_value_get_pointer (value); 00235 break; 00236 default: 00237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 00238 break; 00239 } 00240 } 00241 00242 static void 00243 gschem_pango_renderer_get_property (GObject *object, guint prop_id, 00244 GValue *value, GParamSpec *pspec) 00245 { 00246 GschemPangoRenderer *gschem_renderer = GSCHEM_PANGO_RENDERER (object); 00247 00248 switch (prop_id) { 00249 case PROP_CR: 00250 g_value_set_pointer (value, gschem_renderer->priv->cr); 00251 break; 00252 default: 00253 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 00254 break; 00255 } 00256 } 00257 00258 static void 00259 gschem_pango_renderer_init (GschemPangoRenderer *renderer) 00260 { 00261 renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer, 00262 GSCHEM_TYPE_PANGO_RENDERER, 00263 GschemPangoRendererPrivate); 00264 } 00265 00266 static void 00267 gschem_pango_renderer_class_init (GschemPangoRendererClass *klass) 00268 { 00269 GObjectClass *object_class = G_OBJECT_CLASS (klass); 00270 00271 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); 00272 00273 renderer_class->draw_glyphs = gschem_pango_renderer_draw_glyphs; 00274 renderer_class->draw_rectangle = gschem_pango_renderer_draw_rectangle; 00275 renderer_class->draw_error_underline = gschem_pango_renderer_draw_error_underline; 00276 renderer_class->part_changed = gschem_pango_renderer_part_changed; 00277 renderer_class->begin = gschem_pango_renderer_begin; 00278 renderer_class->end = gschem_pango_renderer_end; 00279 renderer_class->prepare_run = gschem_pango_renderer_prepare_run; 00280 00281 object_class->finalize = gschem_pango_renderer_finalize; 00282 object_class->constructor = gschem_pango_renderer_constructor; 00283 object_class->set_property = gschem_pango_renderer_set_property; 00284 object_class->get_property = gschem_pango_renderer_get_property; 00285 00286 g_object_class_install_property (object_class, 00287 PROP_CR, 00288 g_param_spec_pointer ("cr", 00289 _("cairo context"), 00290 _("the cairo context for the renderer"), 00291 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 00292 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | 00293 G_PARAM_STATIC_BLURB)); 00294 00295 g_type_class_add_private (object_class, sizeof (GschemPangoRendererPrivate)); 00296 } 00297 00307 PangoRenderer * 00308 gschem_pango_renderer_new (cairo_t *cr) 00309 { 00310 return g_object_new (GSCHEM_TYPE_PANGO_RENDERER, "cr", cr, NULL); 00311 } 00312 00313 void 00314 gschem_pango_show_layout (cairo_t *cr, 00315 PangoLayout *pl) 00316 { 00317 static PangoRenderer *renderer = NULL; 00318 static cairo_t *cr_cache = NULL; 00319 double x_off, y_off; 00320 00321 if (cr_cache != cr && renderer != NULL) { 00322 g_object_unref (renderer); 00323 renderer = NULL; 00324 } 00325 00326 if (renderer == NULL) { 00327 renderer = gschem_pango_renderer_new (cr); 00328 cr_cache = cr; 00329 } 00330 00331 cairo_get_current_point (cr, &x_off, &y_off); 00332 00333 pango_renderer_draw_layout (renderer, pl, x_off * PANGO_SCALE, y_off * PANGO_SCALE); 00334 } 00335 00336 00337 /* GschemPangoAttrOverbar */ 00338 00339 static PangoAttribute * 00340 gschem_pango_attr_overbar_copy (const PangoAttribute *attr) 00341 { 00342 const GschemPangoAttrOverbar *e = (const GschemPangoAttrOverbar*) attr; 00343 00344 return gschem_pango_attr_overbar_new (e->overbar); 00345 } 00346 00347 static void 00348 gschem_pango_attr_overbar_destroy (PangoAttribute *attr) 00349 { 00350 g_free (attr); 00351 } 00352 00353 static gboolean 00354 gschem_pango_attr_overbar_compare (const PangoAttribute *attr1, 00355 const PangoAttribute *attr2) 00356 { 00357 const GschemPangoAttrOverbar *e1 = (const GschemPangoAttrOverbar*) attr1; 00358 const GschemPangoAttrOverbar *e2 = (const GschemPangoAttrOverbar*) attr2; 00359 00360 return e1->overbar == e2->overbar; 00361 } 00362 00369 PangoAttribute * 00370 gschem_pango_attr_overbar_new (gboolean overbar) 00371 { 00372 GschemPangoAttrOverbar *result; 00373 00374 static PangoAttrClass klass = { 0, 00375 gschem_pango_attr_overbar_copy, 00376 gschem_pango_attr_overbar_destroy, 00377 gschem_pango_attr_overbar_compare }; 00378 00379 if (!klass.type) 00380 klass.type = gschem_pango_attr_overbar_type = 00381 pango_attr_type_register ("GschemPangoAttrOverbar"); 00382 00383 result = g_new (GschemPangoAttrOverbar, 1); 00384 result->attr.klass = &klass; 00385 result->overbar = overbar; 00386 00387 return (PangoAttribute *)result; 00388 }