]> granicus.if.org Git - graphviz/commitdiff
Cleanup and fixing of various code related to hot spots and HTML labels.
authorerg <devnull@localhost>
Wed, 21 Mar 2007 18:07:54 +0000 (18:07 +0000)
committererg <devnull@localhost>
Wed, 21 Mar 2007 18:07:54 +0000 (18:07 +0000)
In particular:
  HTML labels were not being initialized correctly when used with
graphs or edges
  HTML labels now inherent url info from the object and use that unless
a subpart overrides it.
  There is now more control over which parts of an edge are active. The
URL attribute still provides a default for all pieces, which can be
overridden. We now also give control over the edge and main label
separately, so now the edge, label, headlabel and taillabel can be
independently set.

lib/common/emit.c
lib/common/htmltable.c
lib/common/input.c
lib/common/render.h
lib/common/shapes.c
lib/common/utils.c
lib/gvc/gvcjob.h

index d26924660ad76db5802cd376842ae4e41cae22af..253cb1f818f79e1cc958e37ae7b513a7623755ce 100644 (file)
@@ -69,12 +69,15 @@ void pop_obj_state(GVJ_t *job)
     assert(obj);
 
     free(obj->url);
+    free(obj->labelurl);
     free(obj->tailurl);
     free(obj->headurl);
     free(obj->tooltip);
+    free(obj->labeltooltip);
     free(obj->tailtooltip);
     free(obj->headtooltip);
     free(obj->target);
+    free(obj->labeltarget);
     free(obj->tailtarget);
     free(obj->headtarget);
     free(obj->url_map_p);
@@ -85,39 +88,41 @@ void pop_obj_state(GVJ_t *job)
     free(obj);
 }
 
-void
+/* initMapData:
+ * Store image map data into job, substituting for node, edge, etc.
+ * names.
+ * Return 1 if an assignment was made for url or tooltip or target.
+ */
+int
 initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target,
   void* gobj)
 {
     obj_state_t *obj = job->obj;
     int flags = job->flags;
+    int assigned = 0;
 
     if ((flags & GVRENDER_DOES_LABELS) && lbl)
         obj->label = lbl;
-    if (obj->url) free (obj->url);
     if ((flags & GVRENDER_DOES_MAPS) && url && url[0]) {
         obj->url = strdup_and_subst_obj(url, gobj);
+       assigned = 1;
     }
-    else
-        obj->url = NULL;
-    if (obj->tooltip) free (obj->tooltip);
     if (flags & GVRENDER_DOES_TOOLTIPS) {
         if (tooltip && tooltip[0]) {
             obj->tooltip = strdup_and_subst_obj(tooltip, gobj);
             obj->explicit_tooltip = TRUE;
+           assigned = 1;
         }
         else if (obj->label) {
             obj->tooltip = strdup(obj->label);
+           assigned = 1;
         }
     }
-    else
-        obj->tooltip = NULL;
-    if (obj->target) free (obj->target);
     if ((flags & GVRENDER_DOES_TARGETS) && target && target[0]) {
         obj->target = strdup_and_subst_obj(target, gobj);
+       assigned = 1;
     }
-    else
-        obj->target = NULL;
+    return assigned;
 }
 
 static void
@@ -1524,6 +1529,8 @@ void emit_begin_edge(GVJ_t * job, edge_t * e)
     textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL;
     pointf *pbs = NULL;
     int        i, nump, *pbs_n = NULL, pbs_poly_n = 0;
+    char* dflt_url = NULL;
+    char* dflt_target = NULL;
 
     obj = push_obj_state(job);
     obj->type = EDGE_OBJTYPE;
@@ -1547,38 +1554,72 @@ void emit_begin_edge(GVJ_t * job, edge_t * e)
 
     if (flags & GVRENDER_DOES_MAPS) {
         if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0]))
+            dflt_url = strdup_and_subst_obj(s, (void*)e);
+       if (((s = agget(e, "edgehref")) && s[0]) || ((s = agget(e, "edgeURL")) && s[0]))
             obj->url = strdup_and_subst_obj(s, (void*)e);
-       if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0]))
+       else if (dflt_url)
+           obj->url = strdup(dflt_url);
+       if (((s = agget(e, "labelhref")) && s[0]) || ((s = agget(e, "labelURL")) && s[0]))
+            obj->labelurl = strdup_and_subst_obj(s, (void*)e);
+       else if (dflt_url)
+           obj->labelurl = strdup(dflt_url);
+       if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0])) {
             obj->tailurl = strdup_and_subst_obj(s, (void*)e);
-       else if (obj->url)
-           obj->tailurl = strdup(obj->url);
-       if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0]))
+            obj->explicit_tailurl = TRUE;
+       }
+       else if (dflt_url)
+           obj->tailurl = strdup(dflt_url);
+       if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0])) {
             obj->headurl = strdup_and_subst_obj(s, (void*)e);
-       else if (obj->url)
-           obj->headurl = strdup(obj->url);
+            obj->explicit_headurl = TRUE;
+       }
+       else if (dflt_url)
+           obj->headurl = strdup(dflt_url);
     } 
 
     if (flags & GVRENDER_DOES_TARGETS) {
         if ((s = agget(e, "target")) && s[0])
+            dflt_target = strdup_and_subst_obj(s, (void*)e);
+        if ((s = agget(e, "edgetarget")) && s[0]) {
+           obj->explicit_edgetarget = TRUE;
             obj->target = strdup_and_subst_obj(s, (void*)e);
-        if ((s = agget(e, "tailtarget")) && s[0])
+       }
+       else if (dflt_target)
+           obj->target = strdup(dflt_target);
+        if ((s = agget(e, "labeltarget")) && s[0])
+            obj->labeltarget = strdup_and_subst_obj(s, (void*)e);
+       else if (dflt_target)
+           obj->labeltarget = strdup(dflt_target);
+        if ((s = agget(e, "tailtarget")) && s[0]) {
             obj->tailtarget = strdup_and_subst_obj(s, (void*)e);
-       else if (obj->target)
-           obj->tailtarget = strdup(obj->target);
-        if ((s = agget(e, "headtarget")) && s[0])
+           obj->explicit_tailtarget = TRUE;
+       }
+       else if (dflt_target)
+           obj->tailtarget = strdup(dflt_target);
+        if ((s = agget(e, "headtarget")) && s[0]) {
+           obj->explicit_headtarget = TRUE;
             obj->headtarget = strdup_and_subst_obj(s, (void*)e);
-       else if (obj->target)
-           obj->headtarget = strdup(obj->target);
+       }
+       else if (dflt_target)
+           obj->headtarget = strdup(dflt_target);
     } 
 
     if (flags & GVRENDER_DOES_TOOLTIPS) {
-        if ((s = agget(e, "tooltip")) && s[0]) {
+        if (((s = agget(e, "tooltip")) && s[0]) ||
+            ((s = agget(e, "edgetooltip")) && s[0])) {
             obj->tooltip = strdup_and_subst_obj(s, (void*)e);
            obj->explicit_tooltip = TRUE;
        }
        else if (obj->label)
            obj->tooltip = strdup(obj->label);
 
+        if ((s = agget(e, "labeltooltip")) && s[0]) {
+            obj->labeltooltip = strdup_and_subst_obj(s, (void*)e);
+           obj->explicit_labeltooltip = TRUE;
+       }
+       else if (obj->label)
+           obj->labeltooltip = strdup(obj->label);
+
         if ((s = agget(e, "tailtooltip")) && s[0]) {
             obj->tailtooltip = strdup_and_subst_obj(s, (void*)e);
            obj->explicit_tailtooltip = TRUE;
@@ -1594,6 +1635,9 @@ void emit_begin_edge(GVJ_t * job, edge_t * e)
            obj->headtooltip = strdup(obj->headlabel);
     } 
     
+    free (dflt_url);
+    free (dflt_target);
+
     if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
        if (ED_spl(e) && (obj->url || obj->tooltip) && (flags & GVRENDER_DOES_MAP_POLYGON)) {
            int ns;
@@ -1626,11 +1670,83 @@ void emit_begin_edge(GVJ_t * job, edge_t * e)
        gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
 }
 
+static void
+emit_edge_label(GVJ_t* job, textlabel_t* lbl, int lkind, int explicit,
+    char* url, char* tooltip, char* target, splines* spl)
+{
+    int flags = job->flags;
+    if (lbl == NULL) return;
+    if ((url || explicit) && !(flags & EMIT_CLUSTERS_LAST)) {
+       map_label(job, lbl);
+       gvrender_begin_anchor(job, url, tooltip, target);
+    }
+    emit_label(job, lkind, lbl);
+    if (spl) emit_attachment(job, lbl, spl);
+    if (url || explicit) {
+       if (flags & EMIT_CLUSTERS_LAST) {
+           map_label(job, lbl);
+           gvrender_begin_anchor(job, url, tooltip, target);
+       }
+       gvrender_end_anchor(job);
+    }
+}
+
+/* nodeIntersect:
+ * Common logic for setting hot spots at the beginning and end of 
+ * an edge.
+ * If we are given a value (url, tooltip, target) explicitly set for
+ * the head/tail, we use that. 
+ * Otherwise, if we are given a value explicitly set for the edge,
+ * we use that.
+ * Otherwise, we use whatever the argument value is.
+ * We also note whether or not the tooltip was explicitly set.
+ * If the url is non-NULL or the tooltip was explicit, we set
+ * a hot spot around point p.
+ */
+static void
+nodeIntersect (GVJ_t * job, point p, 
+    boolean explicit_iurl, char* iurl,
+    boolean explicit_itooltip, char* itooltip,
+    boolean explicit_itarget, char* itarget)
+{
+    obj_state_t *obj = job->obj;
+    char* url;
+    char* tooltip;
+    char* target;
+    boolean explicit;
+
+    if (explicit_iurl) url = iurl;
+    else url = obj->url;
+    if (explicit_itooltip) {
+       tooltip = itooltip;
+       explicit = TRUE;
+    }
+    else if (obj->explicit_tooltip) {
+       tooltip = obj->tooltip;
+       explicit = TRUE;
+    }
+    else {
+       explicit = FALSE;
+       tooltip = itooltip;
+    }
+    if (explicit_itarget)
+       target = itarget;
+    else if (obj->explicit_edgetarget)
+       target = obj->target;
+    else
+       target = itarget;
+
+    if (url || explicit) {
+       map_point(job, p);
+       gvrender_begin_anchor(job, url, tooltip, target);
+       gvrender_end_anchor(job);
+    }
+}
+
 void emit_end_edge(GVJ_t * job)
 {
     obj_state_t *obj = job->obj;
     edge_t *e = obj->u.e;
-    bezier bz;
     int i, nump;
 
     if (obj->url || obj->explicit_tooltip) {
@@ -1649,57 +1765,38 @@ void emit_end_edge(GVJ_t * job)
     obj->url_map_n = 0;       /* null out copy so that it doesn't get freed twice */
     obj->url_map_p = NULL;
 
-    /* process intersecion with tail node */
-    if (ED_spl(e) && (obj->tailurl || obj->tailtooltip)) {
+    if (ED_spl(e)) {
+       point p;
+       bezier bz;
+
+       /* process intersection with tail node */
        bz = ED_spl(e)->list[0];
        if (bz.sflag) /* Arrow at start of splines */
-           map_point(job, bz.sp);
+           p = bz.sp;
        else /* No arrow at start of splines */
-           map_point(job, bz.list[0]);
-       gvrender_begin_anchor(job, obj->tailurl, obj->tailtooltip, obj->tailtarget);
-       gvrender_end_anchor(job);
-    }
+           p = bz.list[0];
+       nodeIntersect (job, p, obj->explicit_tailurl, obj->tailurl,
+           obj->explicit_tailtooltip, obj->tailtooltip, 
+           obj->explicit_tailtarget, obj->tailtarget); 
         
-    /* process intersection with head node */
-    if (ED_spl(e) && (obj->headurl || obj->headtooltip)) {
+       /* process intersection with head node */
        bz = ED_spl(e)->list[ED_spl(e)->size - 1];
        if (bz.eflag) /* Arrow at end of splines */
-           map_point(job, bz.ep);
+           p = bz.ep;
        else /* No arrow at end of splines */
-           map_point(job, bz.list[bz.size - 1]);
-       gvrender_begin_anchor(job, obj->headurl, obj->headtooltip, obj->headtarget);
-       gvrender_end_anchor(job);
+           p = bz.list[bz.size - 1];
+       nodeIntersect (job, p, obj->explicit_headurl, obj->headurl,
+           obj->explicit_headtooltip, obj->headtooltip, 
+           obj->explicit_headtarget, obj->headtarget); 
     }
 
-    if (ED_label(e)) {
-        if (obj->url || obj->explicit_tooltip) {
-            map_label(job, ED_label(e));
-           gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
-        }
-       emit_label(job, EMIT_ELABEL, ED_label(e));
-       if (mapbool(late_string(e, E_decorate, "false")) && ED_spl(e))
-           emit_attachment(job, ED_label(e), ED_spl(e));
-       if (obj->url || obj->explicit_tooltip)
-           gvrender_end_anchor(job);
-    }
-    if (ED_head_label(e)) {
-       if (obj->headurl || obj->explicit_headtooltip) {
-           map_label(job, ED_head_label(e));
-           gvrender_begin_anchor(job, obj->headurl, obj->headtooltip, obj->headtarget);
-       }
-       emit_label(job, EMIT_HLABEL, ED_head_label(e)); /* vladimir */
-       if (obj->headurl || obj->explicit_headtooltip)
-           gvrender_end_anchor(job);
-    }
-    if (ED_tail_label(e)) {
-       if (obj->tailurl || obj->explicit_tailtooltip) {
-           map_label(job, ED_tail_label(e));
-           gvrender_begin_anchor(job, obj->tailurl, obj->tailtooltip, obj->tailtarget);
-       }
-       emit_label(job, EMIT_TLABEL, ED_tail_label(e)); /* vladimir */
-       if (obj->tailurl || obj->explicit_tailtooltip)
-           gvrender_end_anchor(job);
-    }
+    emit_edge_label(job, ED_label(e), EMIT_ELABEL, obj->explicit_labeltooltip, 
+       obj->labelurl, obj->labeltooltip, obj->labeltarget, 
+       ((mapbool(late_string(e, E_decorate, "false")) && ED_spl(e)) ? ED_spl(e) : 0));
+    emit_edge_label(job, ED_head_label(e), EMIT_HLABEL, 
+       obj->explicit_headtooltip, obj->headurl, obj->headtooltip, obj->headtarget, 0);
+    emit_edge_label(job, ED_tail_label(e), EMIT_TLABEL, 
+       obj->explicit_tailtooltip, obj->tailurl, obj->tailtooltip, obj->tailtarget, 0);
 
     gvrender_end_edge(job);
     gvrender_end_context(job);
@@ -1987,8 +2084,6 @@ static void emit_view(GVJ_t * job, graph_t * g, int flags)
     edge_t *e;
 
     gvc->common.viewNum++;
-    if (GD_label(g))
-       emit_label(job, EMIT_GLABEL, GD_label(g));
     /* when drawing, lay clusters down before nodes and edges */
     if (!(flags & EMIT_CLUSTERS_LAST))
        emit_clusters(job, g, flags);
@@ -2130,6 +2225,8 @@ void emit_graph(GVJ_t * job, graph_t * g)
            }
            if (job->numLayers == 1)
                emit_background(job, g);
+           if (GD_label(g))
+               emit_label(job, EMIT_GLABEL, GD_label(g));
             if (!(flags & EMIT_CLUSTERS_LAST) && 
                   (obj->url || obj->explicit_tooltip))
                gvrender_end_anchor(job);
@@ -2249,7 +2346,7 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
     edge_t *e;
     obj_state_t *obj;
     textlabel_t *lab;
-    int doAnchor, inAnchor;
+    int doAnchor;
 
     for (c = 1; c <= GD_n_cluster(g); c++) {
        sg = GD_clust(g)[c];
@@ -2264,11 +2361,9 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
        setColorScheme (agget (sg, "colorscheme"));
        gvrender_begin_context(job);
        if (doAnchor && !(flags & EMIT_CLUSTERS_LAST)) {
-           inAnchor = 1;
            emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR);
            gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
        }
-       else inAnchor = 0;
        filled = FALSE;
        istyle = 0;
        if ((style = checkClusterStyle(sg, &istyle))) {
@@ -2335,20 +2430,16 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
                gvrender_box(job, BF, filled);
            }
        }
-       if ((lab = GD_label(sg))) {
-           if (lab->html && inAnchor) {
-               gvrender_end_anchor(job);
-               inAnchor = 0;
-           }
+       if ((lab = GD_label(sg)))
            emit_label(job, EMIT_CLABEL, lab);
-       }
-       if (doAnchor && (flags & EMIT_CLUSTERS_LAST)) {
-           inAnchor = 1;
-           emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR);
-           gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
-       }
-       if (doAnchor)
+
+       if (doAnchor) {
+           if (flags & EMIT_CLUSTERS_LAST) {
+               emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR);
+               gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
+           }
            gvrender_end_anchor(job);
+       }
 
        if (flags & EMIT_PREORDER) {
            for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
index 5a8569f10600dbffcb25d94a88f5f49e8d9fbd03..d642507d3524d0b818b41affb669e6595fc1f193 100644 (file)
@@ -50,6 +50,15 @@ typedef struct {
     graph_t *g;
 } htmlenv_t;
 
+typedef struct {
+    char *url; 
+    char *tooltip;
+    char *target;
+    boolean explicit_tooltip;
+    point LL;
+    point UR;
+} htmlmap_data_t;
+
 #ifdef DEBUG
 static void printCell(htmlcell_t * cp, int ind);
 #endif
@@ -269,27 +278,67 @@ static void doFill(GVJ_t * job, char *color, box B)
 }
 
 /* initAnchor:
+ * Save current map values
  * Initialize fields in job->obj pertaining to anchors.
  * In particular, this also sets the output rectangle.
- * If there is somethine to do, it starts the anchor and returns 1
+ * If there is something to do, close current anchor if
+ * necesary, start the anchor and returns 1.
  * Otherwise, it returns 0.
  *
  * FIX: Should we provide a tooltip if none is set, as is done
  * for nodes, edges, etc. ?
  */
 static int
-initAnchor (GVJ_t* job, htmldata_t* data, box pts)
+initAnchor (GVJ_t* job, htmldata_t* data, box pts, htmlmap_data_t* save,
+    int closePrev)
 {
     obj_state_t *obj = job->obj;
+    int changed;
 
-    initMapData (job, NULL, data->href, data->title, data->target, obj->u.g);
+    save->url = obj->url; 
+    save->tooltip = obj->tooltip;
+    save->target = obj->target;
+    save->explicit_tooltip = obj->explicit_tooltip;
+    changed = initMapData (job, NULL, data->href, data->title, data->target, obj->u.g);
 
-    if (obj->url || obj->tooltip) {
-       emit_map_rect(job, pts.LL, pts.UR);
-       gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
-       return 1;
+    if (changed) {
+       if (closePrev && (save->url || save->explicit_tooltip))
+           gvrender_end_anchor(job);
+       if (obj->url || obj->explicit_tooltip) {
+           emit_map_rect(job, pts.LL, pts.UR);
+           gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
+       }
     }
-    else return 0;
+    return changed;
+}
+
+#define RESET(fld) \
+  if(obj->fld != save->fld) {free(obj->fld); obj->fld = save->fld;}
+
+/* endAnchor:
+ * Pop context pushed by initAnchor.
+ * This is done by ending current anchor, restoring old values and
+ * freeing new, and reopening previous anchor if necessary.
+ *
+ * NB: We don't save or restore geometric map info. This is because
+ * this preservation of map context is only necessary for SVG-like
+ * systems where graphical items are wrapped in an anchor, and we map
+ * top-down. For ordinary map anchors, this is all done bottom-up, so
+ * the geometric map info at the higher level hasn't been emitted yet.
+ */
+static void
+endAnchor (GVJ_t* job, htmlmap_data_t* save, int openPrev)
+{
+    obj_state_t *obj = job->obj;
+
+    if (obj->url || obj->explicit_tooltip)
+       gvrender_end_anchor(job);
+    RESET(url);
+    RESET(tooltip);
+    RESET(target);
+    obj->explicit_tooltip = save->explicit_tooltip;
+    if (openPrev && (obj->url || obj->explicit_tooltip))
+       gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
 }
 
 /* forward declaration */
@@ -302,7 +351,9 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
     point p = env->p;
     htmlcell_t **cells = tbl->u.n.cells;
     htmlfont_t savef;
-    int inAnchor, doAnchor = (tbl->data.href || tbl->data.target);
+    htmlmap_data_t saved;
+    int anchor; /* if true, we need to undo anchor settings. */
+    int doAnchor = (tbl->data.href || tbl->data.target);
 
     if (tbl->font)
        pushFontInfo(env, tbl->font, &savef);
@@ -313,9 +364,9 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
     pts.UR.y += p.y;
 
     if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
-       inAnchor = initAnchor(job, &tbl->data, pts);
+       anchor = initAnchor(job, &tbl->data, pts, &saved, 1);
     else
-       inAnchor = 0;
+       anchor = 0;
 
     if (tbl->data.bgcolor)
        doFill(job, tbl->data.bgcolor, pts);
@@ -323,17 +374,17 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
     if (tbl->data.border)
        doBorder(job, tbl->data.pencolor, tbl->data.border, pts);
 
-    if (inAnchor)
-       gvrender_end_anchor(job);
-
     while (*cells) {
        emit_html_cell(job, *cells, env);
        cells++;
     }
 
+    if (anchor)
+       endAnchor (job, &saved, 1);
+
     if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
-       if (initAnchor(job, &tbl->data, pts))
-           gvrender_end_anchor(job);
+       if (initAnchor(job, &tbl->data, pts, &saved, 0))
+           endAnchor (job, &saved, 0);
     }
 
     if (tbl->font)
@@ -364,6 +415,7 @@ emit_html_img(GVJ_t * job, htmlimg_t * cp, htmlenv_t * env)
 static void
 emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
 {
+    htmlmap_data_t saved;
     box pts = cp->data.box;
     point p = env->p;
     int inAnchor, doAnchor = (cp->data.href || cp->data.target);
@@ -374,7 +426,7 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
     pts.UR.y += p.y;
 
     if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
-       inAnchor = initAnchor(job, &cp->data, pts);
+       inAnchor = initAnchor(job, &cp->data, pts, &saved, 1);
     else
        inAnchor = 0;
 
@@ -385,9 +437,6 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
     if (cp->data.border)
        doBorder(job, cp->data.pencolor, cp->data.border, pts);
 
-    if (inAnchor)
-       gvrender_end_anchor(job);
-
     if (cp->child.kind == HTML_TBL)
        emit_html_tbl(job, cp->child.u.tbl, env);
     else if (cp->child.kind == HTML_IMAGE)
@@ -395,9 +444,12 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
     else
        emit_html_txt(job, cp->child.u.txt, env);
 
+    if (inAnchor)
+       endAnchor (job, &saved, 1);
+
     if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
-       if (initAnchor(job, &cp->data, pts))
-           gvrender_end_anchor(job);
+       if (initAnchor(job, &cp->data, pts, &saved, 0))
+           endAnchor (job, &saved, 0);
     }
 }
 
@@ -405,42 +457,59 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
  * Push new obj on stack to be used in common by all 
  * html elements with anchors.
  * This inherits the type, emit_state, and object of the
- * parent.
+ * parent, as well as the url, explicit, target and tooltip.
  */
 static void
 allocObj (GVJ_t * job)
 {
     obj_state_t *obj;
+    obj_state_t *parent;
 
     obj = push_obj_state(job);
-    obj->type = obj->parent->type;
-    obj->emit_state = obj->parent->emit_state;
+    parent = obj->parent;
+    obj->type = parent->type;
+    obj->emit_state = parent->emit_state;
     switch (obj->type) {
     case NODE_OBJTYPE :
-       obj->u.n = obj->parent->u.n;
+       obj->u.n = parent->u.n;
 #ifdef WITH_CODEGENS
        Obj = NODE;
 #endif
        break;
     case ROOTGRAPH_OBJTYPE :
-       obj->u.g = obj->parent->u.g;
+       obj->u.g = parent->u.g;
 #ifdef WITH_CODEGENS
        Obj = NONE;
 #endif
        break;
     case CLUSTER_OBJTYPE :
-       obj->u.sg = obj->parent->u.sg;
+       obj->u.sg = parent->u.sg;
 #ifdef WITH_CODEGENS
        Obj = CLST;
 #endif
        break;
     case EDGE_OBJTYPE :
-       obj->u.e = obj->parent->u.e;
+       obj->u.e = parent->u.e;
 #ifdef WITH_CODEGENS
        Obj = EDGE;
 #endif
        break;
     }
+    obj->url = parent->url;
+    obj->tooltip = parent->tooltip;
+    obj->target = parent->target;
+    obj->explicit_tooltip = parent->explicit_tooltip;
+}
+
+static void
+freeObj (GVJ_t * job)
+{
+    obj_state_t *obj = job->obj;
+
+    obj->url = NULL;
+    obj->tooltip = NULL;
+    obj->target = NULL;
+    pop_obj_state(job);
 }
 
 /* emit_html_label:
@@ -471,7 +540,7 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp)
     } else {
        emit_html_txt(job, lp->u.txt, &env);
     }
-    pop_obj_state(job);
+    freeObj (job);
 }
 
 void free_html_font(htmlfont_t * fp)
index 9bed14c317d3d8bb0832225c35c00faf4843a47e..cfe6cae12aa8547e91a58a4bf8adac44dd03f955 100644 (file)
@@ -766,12 +766,15 @@ void do_graph_label(graph_t * sg)
     /* it would be nice to allow multiple graph labels in the future */
     if ((p = agget(sg, "label"))) {
        char pos_flag;
-       int html = aghtmlstr(p);
+       int lbl_kind = LT_NONE;
        point dpt;
        pointf dimen;
 
+       if (aghtmlstr(p)) lbl_kind = LT_HTML;
        GD_has_labels(sg->root) |= GRAPH_LABEL;
-       GD_label(sg) = make_label(sg->root, html, strdup_and_subst_obj(p, (void*)sg),
+        if (lbl_kind) p = strdup (p);
+       else p = strdup_and_subst_obj(p, (void*)sg);
+       GD_label(sg) = make_label(sg->root, lbl_kind, p,
                                  late_double(sg,
                                              agfindattr(sg, "fontsize"),
                                              DEFAULT_FONTSIZE, MIN_FONTSIZE),
@@ -781,7 +784,7 @@ void do_graph_label(graph_t * sg)
                                  late_nnstring(sg,
                                                agfindattr(sg, "fontcolor"),
                                                DEFAULT_COLOR));
-       if (html) {
+       if (lbl_kind) {
            if (make_html_label(sg->root, GD_label(sg), sg) == 1)
                agerr(AGPREV, "in label of graph %s\n", sg->name);
        }
index 46830f4af34db8e8e0133b00f8594e1bfc3e709d..119607d76bde76bc3371bdf9650ac88b08616759 100644 (file)
@@ -115,7 +115,7 @@ extern "C" {
     extern void global_def(char *,
                           Agsym_t * (*fun) (Agraph_t *, char *, char *));
     extern int gvRenderJobs (GVC_t * gvc, graph_t * g);
-    extern void initMapData (GVJ_t*, char*, char*, char*, char*, void*);
+    extern int initMapData (GVJ_t*, char*, char*, char*, char*, void*);
     extern boolean isPolygon(node_t *);
     extern char *strdup_and_subst_obj(char *str, void *obj);
     extern char *xml_string(char *s);
index 8308b512107e33ae93a84793fcc3e2f4f8088b69..b2e6309dee90c1c7fda4d93b78786f612a58db51 100644 (file)
@@ -1312,24 +1312,12 @@ static void poly_gencode(GVJ_t * job, node_t * n)
        filled = FALSE;
     }
 
-    if (ND_label(n)->html) {
-       if (doMap && !(job->flags & EMIT_CLUSTERS_LAST))
-            gvrender_end_anchor(job);
-        emit_label(job, EMIT_NLABEL, ND_label(n));
-       if (doMap && (job->flags & EMIT_CLUSTERS_LAST)) {
+    emit_label(job, EMIT_NLABEL, ND_label(n));
+    if (doMap) {
+       if (job->flags & EMIT_CLUSTERS_LAST)
            gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
-            gvrender_end_anchor(job);
-       }
-    }
-    else {
-        emit_label(job, EMIT_NLABEL, ND_label(n));
-        if (doMap) {
-           if (job->flags & EMIT_CLUSTERS_LAST)
-               gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
-            gvrender_end_anchor(job);
-       }
+        gvrender_end_anchor(job);
     }
-
 }
 
 /*=======================end poly======================================*/
@@ -1928,12 +1916,11 @@ static void record_gencode(GVJ_t * job, node_t * n)
     else
        gvrender_box(job, BF, style & FILLED);
 
-    if (doMap && !(job->flags & EMIT_CLUSTERS_LAST))
-        gvrender_end_anchor(job);
-
     gen_fields(job, n, f);
-    if (doMap && (job->flags & EMIT_CLUSTERS_LAST)) {
-        gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
+
+    if (doMap) {
+       if (job->flags & EMIT_CLUSTERS_LAST)
+            gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
         gvrender_end_anchor(job);
     }
 }
@@ -2010,11 +1997,13 @@ static void epsf_gencode(GVJ_t * job, node_t * n)
 {
     obj_state_t *obj = job->obj;
     epsf_t *desc;
+    int doMap = (obj->url || obj->explicit_tooltip);
 
     desc = (epsf_t *) (ND_shape_info(n));
     if (!desc)
        return;
-    if (obj->url || obj->explicit_tooltip)
+
+    if (doMap && !(job->flags & EMIT_CLUSTERS_LAST))
        gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
     gvrender_begin_context(job);
     if (desc)
@@ -2024,8 +2013,11 @@ static void epsf_gencode(GVJ_t * job, node_t * n)
                ND_coord_i(n).y + desc->offset.y, desc->macro_id);
     ND_label(n)->p = ND_coord_i(n);
     gvrender_end_context(job);
-    if (obj->url || obj->explicit_tooltip)
-        gvrender_end_anchor(job);
 
     emit_label(job, EMIT_NLABEL, ND_label(n));
+    if (doMap) {
+       if (job->flags & EMIT_CLUSTERS_LAST)
+           gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
+        gvrender_end_anchor(job);
+    }
 }
index 624488d0dddc479d7c016f4167024a3babf4488a..5ec3a0eac9ad90edaff3b265768824a1fb56f5d9 100644 (file)
@@ -716,24 +716,26 @@ chkPort (port (*pf)(node_t*, char*, char*), node_t* n, char* s)
 int common_init_edge(edge_t * e)
 {
     char *s;
-    int html = 0, r = 0;
+    int r = 0;
     struct fontinfo fi;
     struct fontinfo lfi;
     graph_t *sg = e->tail->graph;
+    int lbl_kind;
 
     fi.fontname = NULL;
     lfi.fontname = NULL;
     if (E_label && (s = agxget(e, E_label->index)) && (s[0])) {
        r = 1;
-       html = aghtmlstr(s);
-       if (html)
+       if (aghtmlstr(s)) lbl_kind = LT_HTML;
+        else lbl_kind = LT_NONE;
+       if (lbl_kind)
            s = strdup(s);
        else
            s = strdup_and_subst_obj(s, (void*)e);
        initFontEdgeAttr(e, &fi);
-       ED_label(e) = make_label(sg->root, html, s,
+       ED_label(e) = make_label(sg->root, lbl_kind, s,
                                fi.fontsize, fi.fontname, fi.fontcolor);
-       if (html) {
+       if (lbl_kind == LT_HTML) {
            if (make_html_label(sg->root, ED_label(e), e) == 1)
                edgeError(e, "label");
        }
@@ -745,31 +747,33 @@ int common_init_edge(edge_t * e)
 
     /* vladimir */
     if (E_headlabel && (s = agxget(e, E_headlabel->index)) && (s[0])) {
-       html = aghtmlstr(s);
-       if (html)
+       if (aghtmlstr(s)) lbl_kind = LT_HTML;
+        else lbl_kind = LT_NONE;
+       if (lbl_kind)
            s = strdup(s);
        else
            s = strdup_and_subst_obj(s, (void*)e);
        initFontLabelEdgeAttr(e, &fi, &lfi);
-       ED_head_label(e) = make_label(sg->root, html, s,
+       ED_head_label(e) = make_label(sg->root, lbl_kind, s,
                                lfi.fontsize, lfi.fontname, lfi.fontcolor);
-       if (html) {
+       if (lbl_kind) {
            if (make_html_label(sg->root, ED_head_label(e), e) == 1)
                edgeError(e, "head label");
        }
        GD_has_labels(sg) |= HEAD_LABEL;
     }
     if (E_taillabel && (s = agxget(e, E_taillabel->index)) && (s[0])) {
-       html = aghtmlstr(s);
-       if (html)
+       if (aghtmlstr(s)) lbl_kind = LT_HTML;
+        else lbl_kind = LT_NONE;
+       if (lbl_kind)
            s = strdup(s);
        else
            s = strdup_and_subst_obj(s, (void*)e);
        if (!lfi.fontname)
            initFontLabelEdgeAttr(e, &fi, &lfi);
-       ED_tail_label(e) = make_label(sg->root, html, s,
+       ED_tail_label(e) = make_label(sg->root, lbl_kind, s,
                                lfi.fontsize, lfi.fontname, lfi.fontcolor);
-       if (html) {
+       if (lbl_kind) {
            if (make_html_label(sg->root, ED_tail_label(e), e) == 1)
                edgeError(e, "tail label");
        }
index e56adc6236f1e449fdbad9d9718d39290ccd3cfb..6f935231fb351ccd4575026a2024076027a64a2d 100644 (file)
@@ -171,20 +171,30 @@ extern "C" {
        char *headlabel; 
 
        char *url;              /* if GVRENDER_DOES_MAPS */
+       char *labelurl;
        char *tailurl;
        char *headurl; 
 
        char *tooltip;          /* if GVRENDER_DOES_TOOLTIPS */
+       char *labeltooltip;
        char *tailtooltip;
        char *headtooltip; 
-       boolean explicit_tooltip;
-       boolean explicit_tailtooltip;
-       boolean explicit_headtooltip;
 
        char *target;           /* if GVRENDER_DOES_TARGETS */
+       char *labeltarget;
        char *tailtarget;
        char *headtarget; 
 
+       int explicit_tooltip:1;
+       int explicit_tailtooltip:1;
+       int explicit_headtooltip:1;
+       int explicit_labeltooltip:1;
+       int explicit_tailtarget:1;
+       int explicit_headtarget:1;
+       int explicit_edgetarget:1;
+       int explicit_tailurl:1;
+       int explicit_headurl:1;
+
        /* primary mapped region - node shape, edge labels */
        map_shape_t url_map_shape; 
        int url_map_n;                  /* number of points for url map if GVRENDER_DOES_MAPS */