157 lines
3.7 KiB
C
157 lines
3.7 KiB
C
#include <TeX/config.h>
|
|
#include <TeX/node.h>
|
|
#include <TeX/flow.h>
|
|
#include <TeX/classes.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
//---
|
|
// Node creation and destruction functions
|
|
//---
|
|
|
|
/* TeX_node_text(): Make a text node */
|
|
struct TeX_Node *TeX_node_text(char const *utf8)
|
|
{
|
|
struct TeX_Node *node = calloc(1, sizeof *node);
|
|
if(!node) return NULL;
|
|
|
|
/* TODO: Don't use strdup(); convert from utf8 instead */
|
|
node->text = malloc(strlen(utf8) + 1);
|
|
if(!node->text) { free(node); return NULL; }
|
|
strcpy((void *)node->text, utf8);
|
|
node->type = TEX_NODECLASS_TEXT;
|
|
|
|
return node;
|
|
}
|
|
|
|
/* TeX_node_command(): Make a command node without arguments */
|
|
struct TeX_Node *TeX_node_command(char const *name)
|
|
{
|
|
/* Get the class id from the class table */
|
|
int type = TeX_class_find(name);
|
|
if(type < 0) return NULL;
|
|
|
|
struct TeX_Node *node = calloc(1, sizeof *node);
|
|
if(!node) return NULL;
|
|
|
|
node->type = type;
|
|
node->next = NULL;
|
|
return node;
|
|
}
|
|
|
|
/* TeX_node_add_arg(): Add an argument to a command node */
|
|
struct TeX_Node *TeX_node_add_arg(struct TeX_Node *node, struct TeX_Flow *arg)
|
|
{
|
|
if(!node || !arg) return node;
|
|
|
|
/* Drop the argument if it's for a plain text node */
|
|
if(node->type == TEX_NODECLASS_TEXT)
|
|
{
|
|
TeX_flow_free(arg);
|
|
return node;
|
|
}
|
|
|
|
/* Otherwise look up a free slot in the argument array of node */
|
|
int i = 0;
|
|
while(i < TEX_NODE_MAX_CHILDREN && node->args[i]) i++;
|
|
|
|
if(i < TEX_NODE_MAX_CHILDREN) node->args[i] = arg;
|
|
else TeX_flow_free(arg);
|
|
|
|
return node;
|
|
}
|
|
|
|
/* TeX_node_absorb(): Absorb text into a command node */
|
|
struct TeX_Node *TeX_node_absorb(struct TeX_Node *node, char const *text)
|
|
{
|
|
char const *class = TeX_class_of(node)->name;
|
|
|
|
if(!strcmp(class, "left") || !strcmp(class, "right"))
|
|
{
|
|
node->subtype = text[0];
|
|
return node;
|
|
}
|
|
|
|
return TeX_node_add_arg(node, TeX_flow_add_node(NULL,
|
|
TeX_node_text(text)));
|
|
}
|
|
|
|
/* TeX_node_free(): Free a TeX_Node and all its children */
|
|
void TeX_node_free(struct TeX_Node *node)
|
|
{
|
|
/* Text nodes: free the allocated string */
|
|
if(node->type == TEX_NODECLASS_TEXT) free(node->text);
|
|
|
|
/* Class nodes: recursively free children */
|
|
else for(int i = 0; i < TEX_NODE_MAX_CHILDREN; i++)
|
|
{
|
|
if(node->args[i]) TeX_flow_free(node->args[i]);
|
|
}
|
|
|
|
/* TODO: Extend with environment nodes */
|
|
|
|
free(node);
|
|
}
|
|
|
|
//---
|
|
// Layout and rendering
|
|
//---
|
|
|
|
/* TeX_node_layout(): Compute the layout of a node */
|
|
void TeX_node_layout(struct TeX_Node *node)
|
|
{
|
|
/* First compute the layout of the children */
|
|
if(node->type != TEX_NODECLASS_TEXT)
|
|
for(int i = 0; i < TEX_NODE_MAX_CHILDREN && node->args[i]; i++)
|
|
TeX_flow_layout(node->args[i]);
|
|
|
|
/* Then use the class' special layout computation function */
|
|
TeX_class_of(node)->layout(node);
|
|
}
|
|
|
|
/* TeX_node_render(): Render a node and its children */
|
|
void TeX_node_render(struct TeX_Node const * node, int x, int y, int color)
|
|
{
|
|
/* Don't render hidden or invalid elements */
|
|
if(node->hidden) return;
|
|
|
|
/* For non trivial classes, use the class' special function */
|
|
TeX_class_of(node)->render(node, x, y, color);
|
|
}
|
|
|
|
//---
|
|
// Printing function
|
|
//---
|
|
|
|
#ifdef TEX_PRINT
|
|
|
|
#include <stdio.h>
|
|
#include <TeX/print.h>
|
|
|
|
/* TeX_print_node(): Print a node's tree */
|
|
void TeX_print_node(struct TeX_Node *node, int indent)
|
|
{
|
|
printf("%*s", indent, "");
|
|
if(!node) { puts("node (null)"); return; }
|
|
|
|
if(node->type == TEX_NODECLASS_TEXT)
|
|
{
|
|
printf("\"%s\"", node->text);
|
|
printf(GRAY " %dx%d,%d %+d%+d" END "\n", node->width,
|
|
node->height, node->line, node->x, node->l);
|
|
}
|
|
else
|
|
{
|
|
printf("<%s>", TeX_class_of(node)->name);
|
|
if(node->subtype)
|
|
printf(" subtype '%c'", node->subtype);
|
|
printf(" "GRAY "%dx%d,%d %+d%+d" END "\n", node->width,
|
|
node->height, node->line, node->x, node->l);
|
|
for(int i = 0; i < TEX_NODE_MAX_CHILDREN && node->args[i]; i++)
|
|
TeX_print_flow(node->args[i], indent + 4);
|
|
}
|
|
}
|
|
|
|
#endif /* TEX_PRINT */
|