function draw(g, state, drawInfo) {
    var x = drawInfo.texArea[0];
    var y = drawInfo.texArea[1];
    var w = drawInfo.texArea[2] - drawInfo.texArea[0];
    var h = drawInfo.texArea[3] - drawInfo.texArea[1];

    var routeInfo = drawInfo.routeInfo;

    var CircularState = {
        NONE: "NONE",
        CLOCKWISE: "CLOCKWISE",
        ANTICLOCKWISE: "ANTICLOCKWISE"
    };

    if (routeInfo != null && routeInfo != undefined) {
        var circularState = routeInfo.circularState;
        var routeColor = routeInfo.routeColor;

        var font = loadResource("font", "mtrsteamloco:fonts/source-han-sans.otf");
        var fontBold = loadResource("font", "mtrsteamloco:fonts/source-han-sans-bold.otf");
        var headAlign = drawInfo.arrowDirection ? Number(drawInfo.arrowDirection) : 0;
        var headString = addPrefix(routeInfo.drawStations[routeInfo.drawStations.length - 1].stationName, "往|To", false);
        var headText = circularState == CircularState.NONE ? routeInfo.drawStations[routeInfo.drawStations.length - 1].stationName : routeInfo.drawStations[drawInfo.index + 1].stationName;
        var strWidth;
        var cjkWidth;
        var nonCjkWidth;
        {
            g.setColor(Color.BLACK);
            if (drawInfo.index == routeInfo.drawStations.length - 1) {
                if (hasCjkPart(headText))
                    if (hasNonCjkPart(headText)) drawStrDL(g, fontBold, font, "终点站|Terminus", widthPercent(0.5), heightPercent(0.3), h * 0.4, 1, 1);
                    else drawStrUnified(g, fontBold, "终点站", widthPercent(0.5), heightPercent(0.65), h * 0.3, 1);
                else drawStrUnified(g, fontBold, "Terminus", widthPercent(0.5), heightPercent(0.65), h * 0.3, 1);
            } else {
                cjkWidth = hasCjkPart(headText)
                    ? hasNonCjkPart(headText)
                        ? getUnifiedStringWidth(g, font, "开往 ", h * 0.2) + getUnifiedStringWidth(g, fontBold, getMatching(headText, true), h * 0.275)
                        : getUnifiedStringWidth(g, font, "开往 ", h * 0.25) + getUnifiedStringWidth(g, fontBold, getMatching(headText, true), h * 0.3)
                    : 0;
                nonCjkWidth = hasNonCjkPart(headText)
                    ? hasCjkPart(headText)
                        ? getUnifiedStringWidth(g, font, `To ${getMatching(headText, false)}`, h * 0.1)
                        : getUnifiedStringWidth(g, font, `To ${getMatching(headText, false)}`, h * 0.3)
                    : 0;
                strWidth = Math.max(cjkWidth, nonCjkWidth);

                var currentX;
                switch (headAlign) {
                    case 0:
                        g.setColor(isLightColor(routeColor) ? Color.BLACK : Color.WHITE);
                        currentX = widthPercent(0.5) - cjkWidth * 0.5;
                        if (hasCjkPart(headText))
                            if (hasNonCjkPart(headText)) {
                                currentX += drawStrUnified(g, font, "开往 ", currentX, heightPercent(0.575), h * 0.275, 0);
                                currentX += drawStrUnified(g, fontBold, getMatching(headText, true), currentX, heightPercent(0.575), h * 0.275, 0);
                                drawStrUnified(g, font, `To ${getMatching(headText, false)}`, widthPercent(0.5), heightPercent(0.7), h * 0.1, 1);
                            } else {
                                currentX += drawStrUnified(g, font, "开往 ", currentX, heightPercent(0.65), h * 0.3, 0);
                                currentX += drawStrUnified(g, fontBold, getMatching(headText, true), currentX, heightPercent(0.65), h * 0.3, 0);
                            }
                        else drawStrUnified(g, font, `To ${getMatching(headText, false)}`, widthPercent(0.5), heightPercent(0.65), h * 0.3, 1);
                        break;
                    case 1:
                        g.setColor(Color.WHITE);
                        g.fillOval(widthPercent(0.5) - strWidth * 0.5 - h * 0.3, heightPercent(0.25), h * 0.5, h * 0.5);
                        g.drawImage(loadResource("img", "fangsu:sign/alb.png"), widthPercent(0.5) - strWidth * 0.5 - h * 0.25, heightPercent(0.3), h * 0.4, h * 0.4, null);
                        g.setColor(isLightColor(routeColor) ? Color.BLACK : Color.WHITE);
                        currentX = widthPercent(0.5) - strWidth * 0.5 + h * 0.225;
                        if (hasCjkPart(headText))
                            if (hasNonCjkPart(headText)) {
                                drawStrUnified(g, font, `To ${getMatching(headText, false)}`, currentX, heightPercent(0.7), h * 0.1, 0);
                                currentX += drawStrUnified(g, font, "开往 ", currentX, heightPercent(0.575), h * 0.275, 0);
                                currentX += drawStrUnified(g, fontBold, getMatching(headText, true), currentX, heightPercent(0.575), h * 0.275, 0);
                            } else {
                                currentX += drawStrUnified(g, font, "开往 ", currentX, heightPercent(0.65), h * 0.3, 0);
                                currentX += drawStrUnified(g, fontBold, getMatching(headText, true), currentX, heightPercent(0.65), h * 0.3, 0);
                            }
                        else drawStrUnified(g, font, `To ${getMatching(headText, false)}`, currentX, heightPercent(0.65), h * 0.3, 0);
                        break;
                    case 2:
                        g.setColor(Color.WHITE);
                        g.fillOval(widthPercent(0.5) + strWidth * 0.5 - h * 0.25, heightPercent(0.25), h * 0.5, h * 0.5);
                        g.drawImage(loadResource("img", "fangsu:sign/arb.png"), widthPercent(0.5) + strWidth * 0.5 - h * 0.2, heightPercent(0.3), h * 0.4, h * 0.4, null);
                        g.setColor(isLightColor(routeColor) ? Color.BLACK : Color.WHITE);
                        currentX = widthPercent(0.5) + strWidth * 0.5 - h * 0.225;
                        if (hasCjkPart(headText))
                            if (hasNonCjkPart(headText)) {
                                drawStrUnified(g, font, `To ${getMatching(headText, false)}`, currentX, heightPercent(0.7), h * 0.1, 2);
                                currentX -= drawStrUnified(g, fontBold, getMatching(headText, true), currentX, heightPercent(0.575), h * 0.275, 2);
                                currentX -= drawStrUnified(g, font, "开往 ", currentX, heightPercent(0.575), h * 0.275, 2);
                            } else {
                                currentX -= drawStrUnified(g, font, "开往 ", currentX, heightPercent(0.65), h * 0.3, 0);
                                currentX -= drawStrUnified(g, fontBold, getMatching(headText, true), currentX, heightPercent(0.65), h * 0.3, 0);
                            }
                        else drawStrUnified(g, font, `To ${getMatching(headText, false)}`, currentX, heightPercent(0.65), h * 0.3, 2);
                        break;
                }
            }
        }
    }

    function widthPercent(p) {
        return x + w * p;
    }
    function heightPercent(p) {
        return y + h * p;
    }
}
