Skip to content

Commit

Permalink
Merge pull request from GHSA-r8vr-c48j-fcc5
Browse files Browse the repository at this point in the history
Fix quadratic behavior in rendering
  • Loading branch information
anticomputer authored Mar 31, 2023
2 parents 2300c1b + bd4f96e commit 07a66c9
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 100 deletions.
52 changes: 19 additions & 33 deletions src/commonmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,8 @@ static bool is_autolink(cmark_node *node) {
link_text->as.literal.len) == 0);
}

// if node is a block node, returns node.
// otherwise returns first block-level node that is an ancestor of node.
// if there is no block-level ancestor, returns NULL.
static cmark_node *get_containing_block(cmark_node *node) {
while (node) {
if (CMARK_NODE_BLOCK_P(node)) {
return node;
} else {
node = node->parent;
}
}
return NULL;
}

static int S_render_node(cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
cmark_node *tmp;
int list_number;
cmark_delim_type list_delim;
int numticks;
Expand All @@ -189,14 +174,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
// Don't adjust tight list status til we've started the list.
// Otherwise we loose the blank line between a paragraph and
// a following list.
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
tmp = get_containing_block(node);
renderer->in_tight_list_item =
tmp && // tmp might be NULL if there is no containing block
((tmp->type == CMARK_NODE_ITEM &&
cmark_node_get_list_tight(tmp->parent)) ||
(tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
cmark_node_get_list_tight(tmp->parent->parent)));
if (entering) {
if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
renderer->in_tight_list_item = node->parent->parent->as.list.tight;
}
} else {
if (node->type == CMARK_NODE_LIST) {
renderer->in_tight_list_item =
node->parent &&
node->parent->type == CMARK_NODE_ITEM &&
node->parent->parent->as.list.tight;
}
}

if (node->extension && node->extension->commonmark_render_func) {
Expand Down Expand Up @@ -228,19 +216,15 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
LIT("<!-- end list -->");
BLANKLINE();
}
renderer->list_number = cmark_node_get_list_start(node);
break;

case CMARK_NODE_ITEM:
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
marker_width = 4;
} else {
list_number = cmark_node_get_list_start(node->parent);
list_number = renderer->list_number++;
list_delim = cmark_node_get_list_delim(node->parent);
tmp = node;
while (tmp->prev) {
tmp = tmp->prev;
list_number += 1;
}
// we ensure a width of at least 4 so
// we get nice transition from single digits
// to double
Expand Down Expand Up @@ -405,10 +389,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
break;

case CMARK_NODE_STRONG:
if (entering) {
LIT("**");
} else {
LIT("**");
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
if (entering) {
LIT("**");
} else {
LIT("**");
}
}
break;

Expand Down
10 changes: 6 additions & 4 deletions src/html.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
break;

case CMARK_NODE_STRONG:
if (entering) {
cmark_strbuf_puts(html, "<strong>");
} else {
cmark_strbuf_puts(html, "</strong>");
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
if (entering) {
cmark_strbuf_puts(html, "<strong>");
} else {
cmark_strbuf_puts(html, "</strong>");
}
}
break;

Expand Down
10 changes: 6 additions & 4 deletions src/latex.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
break;

case CMARK_NODE_STRONG:
if (entering) {
LIT("\\textbf{");
} else {
LIT("}");
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
if (entering) {
LIT("\\textbf{");
} else {
LIT("}");
}
}
break;

Expand Down
19 changes: 8 additions & 11 deletions src/man.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ static void S_outc(cmark_renderer *renderer, cmark_node *node,

static int S_render_node(cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
cmark_node *tmp;
int list_number;
bool entering = (ev_type == CMARK_EVENT_ENTER);
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
Expand Down Expand Up @@ -114,6 +113,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
break;

case CMARK_NODE_LIST:
renderer->list_number = cmark_node_get_list_start(node);
break;

case CMARK_NODE_ITEM:
Expand All @@ -123,12 +123,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
LIT("\\[bu] 2");
} else {
list_number = cmark_node_get_list_start(node->parent);
tmp = node;
while (tmp->prev) {
tmp = tmp->prev;
list_number += 1;
}
list_number = renderer->list_number++;
char list_number_s[LIST_NUMBER_SIZE];
snprintf(list_number_s, LIST_NUMBER_SIZE, "\"%d.\" 4", list_number);
LIT(list_number_s);
Expand Down Expand Up @@ -225,10 +220,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
break;

case CMARK_NODE_STRONG:
if (entering) {
LIT("\\f[B]");
} else {
LIT("\\f[]");
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
if (entering) {
LIT("\\f[B]");
} else {
LIT("\\f[]");
}
}
break;

Expand Down
8 changes: 8 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ struct cmark_node {

cmark_syntax_extension *extension;

/**
* Used during cmark_render() to cache the most recent non-NULL
* extension, if you go up the parent chain like this:
*
* node->parent->...parent->extension
*/
cmark_syntax_extension *ancestor_extension;

union {
int ref_ix;
int def_count;
Expand Down
42 changes: 13 additions & 29 deletions src/plaintext.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,8 @@ static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_node *node,
cmark_render_code_point(renderer, c);
}

// if node is a block node, returns node.
// otherwise returns first block-level node that is an ancestor of node.
// if there is no block-level ancestor, returns NULL.
static cmark_node *get_containing_block(cmark_node *node) {
while (node) {
if (CMARK_NODE_BLOCK_P(node)) {
return node;
} else {
node = node->parent;
}
}
return NULL;
}

static int S_render_node(cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
cmark_node *tmp;
int list_number;
cmark_delim_type list_delim;
int i;
Expand All @@ -46,14 +31,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
// Don't adjust tight list status til we've started the list.
// Otherwise we loose the blank line between a paragraph and
// a following list.
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
tmp = get_containing_block(node);
renderer->in_tight_list_item =
tmp && // tmp might be NULL if there is no containing block
((tmp->type == CMARK_NODE_ITEM &&
cmark_node_get_list_tight(tmp->parent)) ||
(tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
cmark_node_get_list_tight(tmp->parent->parent)));
if (entering) {
if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
renderer->in_tight_list_item = node->parent->parent->as.list.tight;
}
} else {
if (node->type == CMARK_NODE_LIST) {
renderer->in_tight_list_item =
node->parent &&
node->parent->type == CMARK_NODE_ITEM &&
node->parent->parent->as.list.tight;
}
}

if (node->extension && node->extension->plaintext_render_func) {
Expand All @@ -73,19 +61,15 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
node->next->type == CMARK_NODE_LIST)) {
CR();
}
renderer->list_number = cmark_node_get_list_start(node);
break;

case CMARK_NODE_ITEM:
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
marker_width = 4;
} else {
list_number = cmark_node_get_list_start(node->parent);
list_number = renderer->list_number++;
list_delim = cmark_node_get_list_delim(node->parent);
tmp = node;
while (tmp->prev) {
tmp = tmp->prev;
list_number += 1;
}
// we ensure a width of at least 4 so
// we get nice transition from single digits
// to double
Expand Down
17 changes: 8 additions & 9 deletions src/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ static void S_out(cmark_renderer *renderer, cmark_node *node,
cmark_chunk remainder = cmark_chunk_literal("");
int k = renderer->buffer->size - 1;

cmark_syntax_extension *ext = NULL;
cmark_node *n = node;
while (n && !ext) {
ext = n->extension;
if (!ext)
n = n->parent;
}
cmark_syntax_extension *ext = node->ancestor_extension;
if (ext && !ext->commonmark_escape_func)
ext = NULL;

Expand Down Expand Up @@ -177,11 +171,16 @@ char *cmark_render(cmark_mem *mem, cmark_node *root, int options, int width,

cmark_renderer renderer = {mem, &buf, &pref, 0, width,
0, 0, true, true, false,
false, outc, S_cr, S_blankline, S_out,
0};
false, 0, outc, S_cr, S_blankline,
S_out, 0};

while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cur = cmark_iter_get_node(iter);
if (cur->extension) {
cur->ancestor_extension = cur->extension;
} else if (cur->parent) {
cur->ancestor_extension = cur->parent->ancestor_extension;
}
if (!render_node(&renderer, cur, ev_type, options)) {
// a false value causes us to skip processing
// the node's contents. this is used for
Expand Down
1 change: 1 addition & 0 deletions src/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct cmark_renderer {
bool begin_content;
bool no_linebreaks;
bool in_tight_list_item;
int list_number;
void (*outc)(struct cmark_renderer *, cmark_node *, cmark_escaping, int32_t, unsigned char);
void (*cr)(struct cmark_renderer *);
void (*blankline)(struct cmark_renderer *);
Expand Down
3 changes: 2 additions & 1 deletion src/xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "syntax_extension.h"

#define BUFFER_SIZE 100
#define MAX_INDENT 40

// Functions to convert cmark_nodes to XML strings.

Expand All @@ -26,7 +27,7 @@ struct render_state {

static CMARK_INLINE void indent(struct render_state *state) {
int i;
for (i = 0; i < state->indent; i++) {
for (i = 0; i < state->indent && i < MAX_INDENT; i++) {
cmark_strbuf_putc(state->xml, ' ');
}
}
Expand Down
18 changes: 9 additions & 9 deletions test/spec.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6926,7 +6926,7 @@ foo__bar__
```````````````````````````````` example
__foo, __bar__, baz__
.
<p><strong>foo, <strong>bar</strong>, baz</strong></p>
<p><strong>foo, bar, baz</strong></p>
````````````````````````````````


Expand Down Expand Up @@ -7197,7 +7197,7 @@ foo***bar***baz
```````````````````````````````` example
foo******bar*********baz
.
<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
<p>foo<strong>bar</strong>***baz</p>
````````````````````````````````


Expand Down Expand Up @@ -7268,21 +7268,21 @@ __foo _bar_ baz__
```````````````````````````````` example
__foo __bar__ baz__
.
<p><strong>foo <strong>bar</strong> baz</strong></p>
<p><strong>foo bar baz</strong></p>
````````````````````````````````


```````````````````````````````` example
____foo__ bar__
.
<p><strong><strong>foo</strong> bar</strong></p>
<p><strong>foo bar</strong></p>
````````````````````````````````


```````````````````````````````` example
**foo **bar****
.
<p><strong>foo <strong>bar</strong></strong></p>
<p><strong>foo bar</strong></p>
````````````````````````````````


Expand Down Expand Up @@ -7567,14 +7567,14 @@ switching delimiters:
```````````````````````````````` example
****foo****
.
<p><strong><strong>foo</strong></strong></p>
<p><strong>foo</strong></p>
````````````````````````````````


```````````````````````````````` example
____foo____
.
<p><strong><strong>foo</strong></strong></p>
<p><strong>foo</strong></p>
````````````````````````````````


Expand All @@ -7585,7 +7585,7 @@ delimiters:
```````````````````````````````` example
******foo******
.
<p><strong><strong><strong>foo</strong></strong></strong></p>
<p><strong>foo</strong></p>
````````````````````````````````


Expand All @@ -7601,7 +7601,7 @@ Rule 14:
```````````````````````````````` example
_____foo_____
.
<p><em><strong><strong>foo</strong></strong></em></p>
<p><em><strong>foo</strong></em></p>
````````````````````````````````


Expand Down

0 comments on commit 07a66c9

Please sign in to comment.