@Override
	public void labelEdge(RenderContext<V, E> rc, Layout<V, E> layout, E e, String text) {

		Graph<V, E> jungGraph = layout.getGraph();
		if (!rc.getEdgeIncludePredicate().apply(Context.getInstance(jungGraph, e))) {
			return;
		}

		Pair<V> endpoints = jungGraph.getEndpoints(e);
		V startv = endpoints.getFirst();
		V endv = endpoints.getSecond();

		Predicate<Context<Graph<V, E>, V>> includeVertex = rc.getVertexIncludePredicate();
		if (!includeVertex.apply(Context.getInstance(jungGraph, startv)) ||
			!includeVertex.apply(Context.getInstance(jungGraph, endv))) {
			return;
		}

		Point2D start = layout.apply(startv);
		MultiLayerTransformer multiLayerTransformer = rc.getMultiLayerTransformer();
		start = multiLayerTransformer.transform(Layer.LAYOUT, start);

		Shape vertexShape = vertexShapeTransformer.apply(startv);
		Rectangle vertexBounds = vertexShape.getBounds();
		int xDisplacement = rc.getLabelOffset();

		Point2D labelPointOffset = new Point2D.Double();

		// note: location is centered
		double cx = start.getX();
		double cy = start.getY();

		EdgeLabelRenderer labelRenderer = rc.getEdgeLabelRenderer();
		Font font = rc.getEdgeFontTransformer().apply(e);
		boolean isSelected = rc.getPickedEdgeState().isPicked(e);
		Component component = labelRenderer.getEdgeLabelRendererComponent(rc.getScreenDevice(),
			text, font, isSelected, e);
		int labelWidth = component.getPreferredSize().width;

		List<Point2D> articulationPoints = e.getArticulationPoints();
		if (articulationPoints.isEmpty()) {
			double vertexBottom = start.getY() + (vertexBounds.height >> 1); // location is centered
			double textY = (int) (vertexBottom + edgeOffset); // below the vertex; above the bend 
			double textX = (int) (start.getX() + xDisplacement); // right of the edge
			labelPointOffset.setLocation(textX, textY);
		}
		else if (articulationPoints.size() == 1) {
			// articulation must have been removed
			return;
		}
		else {

			Point2D bend1 = articulationPoints.get(0);
			bend1 = multiLayerTransformer.transform(Layer.LAYOUT, bend1);
			Point2D bend2 = articulationPoints.get(1);
			bend2 = multiLayerTransformer.transform(Layer.LAYOUT, bend2);

			double vertexSide = cx + (vertexBounds.width >> 1);
			double vertexBottom = cy + (vertexBounds.height >> 1);

			double bx1 = bend1.getX();

			FlowType flow = e.getFlowType();
			boolean isRight = flow.isFallthrough() || flow.isUnConditional();

			if (articulationPoints.size() == 2) {

				double textX = (int) (vertexSide + edgeOffset); // right of the vertex 
				double textY = (int) (cy + edgeOffset); // above the edge 
				labelPointOffset.setLocation(textX, textY);
			}
			else { // 3 or 4 articulations

				double textY = (int) (vertexBottom + edgeOffset); // below the vertex; above the bend 
				double textX = (int) (bx1 + xDisplacement); // right of the edge
				if (!isRight) {
					textX = bx1 - xDisplacement - labelWidth;
				}

				labelPointOffset.setLocation(textX, textY);
			}
		}

		Dimension d = component.getPreferredSize();

		GraphicsDecorator g = rc.getGraphicsContext();
		AffineTransform old = g.getTransform();
		AffineTransform xform = new AffineTransform(old);
		xform.translate(labelPointOffset.getX(), labelPointOffset.getY());

		g.setTransform(xform);
		g.draw(component, rc.getRendererPane(), 0, 0, d.width, d.height, true);
		g.setTransform(old);

		// debug
		//labelArticulations(component, g, rc, e);
	}
An edge label renderer used with the {@link DecompilerNestedLayout}

@param <V> the vertex type
@param <E> the edge type
Ghidra/Features/FunctionGraphDecompilerExtension/src/main/java/ghidra/app/plugin/core/functiongraph/graph/layout/DNLEdgeLabelRenderer.java