void fill_span_from_shadow (hf_type *buffer_in, hf_type *buffer_out, gint xmax, gint ymax, hf_type v1, hf_type v2, hf_type filling_value, gint y, gint x1, gint x2, gint direction, gint select_mode) { gint i, mark1, mark2; glong value_to_test; hf_type output_value; gboolean span_end, filled, to_fill; filled = FALSE; // printf("FILLING y = %d, from x = %d to %d, direction = %d; value: %d\n",y, x1, x2, direction, filling_value); if (write_span(y,encode_span(direction,x1,x2))) { // printf("FILLING in DOUBLE y = %d, from x = %d to %d, direction = %s; value: %d; mode: %s\n",y, x1, x2, // ((direction==0)?"FILL_UP":((direction==1)?"FILL_DOWN":"FILL_BOTH")), filling_value, // ((select_mode==0)?"SELECT_REPLACE":((select_mode==1)?"SELECT_ADD":"SELECT_SUBTRACT"))); return; } // Direction: FILL_UP (North), FILL_DOWN (South), FILL_BOTH if ( direction==FILL_BOTH ) { if ( (y-1) >= 0 ) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x1, x2, FILL_UP, select_mode); if ( (y+1) <= ymax) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x1, x2, FILL_DOWN, select_mode); return; } // 1. Calculate direction (FILL_UP or FILL_DOWN) if ( direction==FILL_UP ) y--; else y++; // Test the boundaries in case the function is called // at the first recursivity level with direction <> FILL_BOTH if ( (y<0) || (y>=ymax) ) return; // 2. Process span // 2.1 Backup original span mark1 = x1; mark2 = x2; // 2.2 For x1, if the filling test is true, extend the span as needed output_value = *(buffer_out + VECTORIZE(x1,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(x1,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(x1,y,xmax))) + ((glong) output_value); if ( test_fill (value_to_test, v1, v2, select_mode, output_value) ) { // Filling test is true, we extend the span backwards, filling pixels for (mark1 = x1-1; mark1>=0; mark1--) { output_value = *(buffer_out + VECTORIZE(mark1,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(mark1,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(mark1,y,xmax))) + ((glong) output_value); // Stop when the filling test is false if (! test_fill (value_to_test, v1, v2, select_mode, output_value)){ break; } else *(buffer_out + VECTORIZE(mark1,y,xmax)) = filling_value; } mark1++; } else { // If the filling test is false, narrow the span as needed while ( mark1<=mark2 ) { mark1++; output_value = *(buffer_out + VECTORIZE(mark1,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(mark1,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(mark1,y,xmax))) + ((glong) output_value); if ( test_fill (value_to_test, v1, v2, select_mode, output_value) ) break; } } if (mark1>mark2) return; // Run from mark1 through mark2, filling pixels and calling recursively fill_from_shadow // for the current span, each time a discontinuity is encountered // At this point, the filling test is true for mark1 // If mark1 < x1, then the mark1-x1 range is already filled, including x1 span_end = FALSE; // We don't need to fill pixels before x1, // but we need mark1 to specify the shadow for the span on the next y i = MAX(x1,mark1); // We need to fill the shadow between x1 and mark1, if mark1<(x1-1) if (mark1<(x1-1)) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, mark1, x1, ((direction==FILL_UP) ? FILL_DOWN : FILL_UP ), select_mode ); to_fill = TRUE; while (i<=mark2) { // count++; // if (i==384) // printf("Count: %d; I: %d; Mark1: %d; Mark2: %d\n",count, i, mark1, mark2); if ( to_fill ) { *(buffer_out + VECTORIZE(i,y,xmax)) = filling_value; if (span_end) // begin a new span mark1 = i; span_end = FALSE; filled = TRUE; } else { // The first time the fill condition is false, a span has ended, // we must call "fill_from_shadow" for this span // After, we're looking for the beginning of a new span if ( (!span_end) && (i>x1)) { fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1, v2, filling_value, y, mark1, i-1, direction, select_mode); // If the new span boundary exceeds the old one by more than one pixel, // we start a filling movement on the other direction if ( (i-1) > x2 ) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x2+1, i-1, ((direction==FILL_UP) ? FILL_DOWN : FILL_UP ), select_mode ); span_end = TRUE; filled = TRUE; } mark1 = i+1; if (mark1>=x2) break; } i++; if (i==xmax) break; output_value = *(buffer_out + VECTORIZE(i,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(i,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(i,y,xmax))) + ((glong) output_value); if ( test_fill (value_to_test, v1, v2, select_mode, output_value) ) { to_fill = TRUE; if (i>x2) { mark2++; // We extend the span as necessary if (mark2==xmax) { mark2--; break; } } } else to_fill = FALSE; } // "Flush" the last span if required if (filled && ((i>mark2) || (i==xmax-1))) { fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, mark1, mark2, direction, select_mode); // If the new span boundary exceeds the old one by more than one pixel, // we start a filling movement on the other direction if ( mark2 > x2 ) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x2+1, mark2, ((direction==FILL_UP) ? FILL_DOWN : FILL_UP ), select_mode ); } }
/* * escape_to_html */ VALUE escape_to_html(VALUE self, VALUE rawdata) { VALUE result; if (rawdata == Qnil) { return rb_str_new2(""); } if (TYPE(rawdata) != T_STRING) { rb_raise(rb_eTypeError, "invalid type for rawdata"); return Qnil; } char *dataStr = StringValueCStr(rawdata); size_t dataStrLen = strlen(dataStr); char code[CODE_BUF_SIZE]; bool inCode = false; size_t in_pos = 0, scratch_pos = 0, code_pos = 0; /* * Pre alloc scratch space that's at least as big as the input string, plus * some space for inserted span elements. * * Every string gets wrapped in a <span class="ansible_none"></span> * * Assume that every new escape code that's encountered will produce open * and close span tags that together consume 100 bytes (this allows for 3-5 * codes per span, which is generous). This should be good enough for * pretty much everything. If it's not, we'll still notice when we run out * of space and try to realloc. */ int spans = 1 + count_escapes(dataStr, dataStrLen); size_t scratchLen = dataStrLen + (spans * MAX_SPAN_SIZE); char *scratch = malloc(scratchLen); memset(scratch, 0, scratchLen); write_scratch((char *)SPAN_START(ansible_none), sizeof(SPAN_START(ansible_none))-1, &scratch, &scratch_pos, &scratchLen); for (; in_pos < dataStrLen; in_pos++) { char c = dataStr[in_pos]; /* * Copy characters into scratch that arent within an escape code block. */ if (c == '\033') { // Enter escape code on ^[ inCode = true; code_pos = 0; } else if (c == 'm') { if (inCode) { // Exit escape code on m inCode = false; code[code_pos] = 0; DBG("code: %s\n", code); write_span(code, &scratch, &scratch_pos, &scratchLen); } else { // Copy an m that's not terminating an escape code write_scratch(&c, 1, &scratch, &scratch_pos, &scratchLen); } } else if (!inCode) { // Copy everything else write_scratch(&c, 1, &scratch, &scratch_pos, &scratchLen); } else { // fill code buffer if (code_pos < sizeof(code)) { code[code_pos++] = c; } } } write_scratch((char *)SPAN_CLOSE, sizeof(SPAN_CLOSE)-1, &scratch, &scratch_pos, &scratchLen); result = rb_enc_str_new(scratch, scratch_pos, rb_enc_find("BINARY")); free(scratch); return result; }