gschem

gschem_pango.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines