21# include "config_auto.h"
36static WERD *add_repeated_word(WERD_IT *rep_it, int16_t &rep_left, int16_t &prev_chop_coord,
37 uint8_t &blanks,
float pitch, WERD_IT *word_it);
39static void fixed_chop_cblob(
C_BLOB *blob, int16_t chop_coord,
float pitch_error,
40 C_OUTLINE_LIST *left_outlines, C_OUTLINE_LIST *right_outlines);
42static void fixed_split_coutline(
C_OUTLINE *srcline, int16_t chop_coord,
float pitch_error,
43 C_OUTLINE_IT *left_it, C_OUTLINE_IT *right_it);
45static bool fixed_chop_coutline(
C_OUTLINE *srcline, int16_t chop_coord,
float pitch_error,
46 C_OUTLINE_FRAG_LIST *left_frags, C_OUTLINE_FRAG_LIST *right_frags);
48static void save_chop_cfragment(int16_t head_index,
ICOORD head_pos, int16_t tail_index,
51static void add_frag_to_list(
C_OUTLINE_FRAG *frag, C_OUTLINE_FRAG_LIST *frags);
53static void close_chopped_cfragments(C_OUTLINE_FRAG_LIST *frags, C_OUTLINE_LIST *children,
54 float pitch_error, C_OUTLINE_IT *dest_it);
73 int16_t prev_chop_coord;
76 C_OUTLINE_LIST left_coutlines;
77 C_OUTLINE_LIST right_coutlines;
79 C_BLOB_IT cblob_it = &cblobs;
81 WERD_IT word_it = &words;
92#ifndef GRAPHICS_DISABLED
101 if (rep_it.empty()) {
102 rep_left = INT16_MAX;
104 rep_left = rep_it.data()->bounding_box().left();
106 if (box_it.empty()) {
109 xstarts[0] = box_it.data()->bounding_box().left();
110 if (rep_left < xstarts[0]) {
111 xstarts[0] = rep_left;
113 if (cell_it.empty() || row->
char_cells.singleton()) {
114 tprintf(
"Row without enough char cells!\n");
115 tprintf(
"Leftmost blob is at (%d,%d)\n", box_it.data()->bounding_box().left(),
116 box_it.data()->bounding_box().bottom());
120 prev_chop_coord = cell_it.data()->x();
122 while (rep_left < cell_it.data()->x()) {
124 add_repeated_word(&rep_it, rep_left, prev_chop_coord, blanks, row->
fixed_pitch, &word_it);
126 cell_it.mark_cycle_pt();
127 if (prev_chop_coord >= cell_it.data()->x()) {
130 for (; !cell_it.cycled_list(); cell_it.forward()) {
131 chop_coord = cell_it.data()->x();
132 while (!box_it.empty() && box_it.data()->bounding_box().left() <= chop_coord) {
133 if (box_it.data()->bounding_box().right() > prev_x) {
134 prev_x = box_it.data()->bounding_box().right();
139 while (!box_it.empty() && box_it.data()->cblob() ==
nullptr) {
140 delete box_it.extract();
144 if (!right_coutlines.empty() && left_coutlines.empty()) {
148 if (!left_coutlines.empty()) {
149 cblob_it.add_after_then_move(
new C_BLOB(&left_coutlines));
151 if (rep_left < chop_coord) {
152 if (rep_left > prev_chop_coord) {
154 static_cast<uint8_t
>(floor((rep_left - prev_chop_coord) / row->
fixed_pitch + 0.5));
159 if (chop_coord > prev_chop_coord) {
161 static_cast<uint8_t
>(floor((chop_coord - prev_chop_coord) / row->
fixed_pitch + 0.5));
166 if (!cblob_it.empty()) {
167 if (blanks < 1 && word != nullptr && !word->flag(
W_REP_CHAR)) {
170 word =
new WERD(&cblobs, blanks,
nullptr);
171 cblob_it.set_to_list(&cblobs);
173 word_it.add_after_then_move(word);
180 blanks += new_blanks;
182 while (rep_left < chop_coord) {
183 word = add_repeated_word(&rep_it, rep_left, prev_chop_coord, blanks, row->
fixed_pitch,
187 if (prev_chop_coord < chop_coord) {
188 prev_chop_coord = chop_coord;
191 if (!cblob_it.empty()) {
192 word =
new WERD(&cblobs, blanks,
nullptr);
194 word_it.add_after_then_move(word);
200 while (!rep_it.empty()) {
201 add_repeated_word(&rep_it, rep_left, prev_chop_coord, blanks, row->
fixed_pitch, &word_it);
204 word_it.data()->set_flag(
W_EOL,
true);
205 if (prev_chop_coord > prev_x) {
206 prev_x = prev_chop_coord;
208 xstarts[1] = prev_x + 1;
211 word_it.set_to_list(real_row->
word_list());
213 word_it.add_list_after(&words);
224static WERD *add_repeated_word(
227 int16_t &prev_chop_coord,
235 if (rep_left > prev_chop_coord) {
236 new_blanks =
static_cast<uint8_t
>(floor((rep_left - prev_chop_coord) / pitch + 0.5));
237 blanks += new_blanks;
239 word = rep_it->extract();
241 word_it->add_after_then_move(word);
242 word->set_blanks(blanks);
244 if (rep_it->empty()) {
245 rep_left = INT16_MAX;
247 rep_left = rep_it->data()->bounding_box().left();
264 C_OUTLINE_LIST *left_coutlines,
265 C_OUTLINE_LIST *right_coutlines) {
268 if (blob !=
nullptr) {
271 real_cblob =
nullptr;
273 if (!right_coutlines->empty() || real_cblob !=
nullptr) {
274 fixed_chop_cblob(real_cblob, chop_coord, pitch_error, left_coutlines, right_coutlines);
287static void fixed_chop_cblob(
291 C_OUTLINE_LIST *left_outlines,
292 C_OUTLINE_LIST *right_outlines
294 C_OUTLINE *old_right;
295 C_OUTLINE_LIST new_outlines;
297 C_OUTLINE_IT left_it = left_outlines;
299 C_OUTLINE_IT right_it = right_outlines;
300 C_OUTLINE_IT new_it = &new_outlines;
301 C_OUTLINE_IT blob_it;
303 if (!right_it.empty()) {
304 while (!right_it.empty()) {
305 old_right = right_it.extract();
307 fixed_split_coutline(old_right, chop_coord, pitch_error, &left_it, &new_it);
309 right_it.add_list_before(&new_outlines);
311 if (blob !=
nullptr) {
312 blob_it.set_to_list(blob->out_list());
313 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
314 fixed_split_coutline(blob_it.extract(), chop_coord, pitch_error, &left_it, &right_it);
327static void fixed_split_coutline(
331 C_OUTLINE_IT *left_it,
332 C_OUTLINE_IT *right_it
336 C_OUTLINE_LIST left_ch;
337 C_OUTLINE_LIST right_ch;
338 C_OUTLINE_FRAG_LIST left_frags;
339 C_OUTLINE_FRAG_LIST right_frags;
341 C_OUTLINE_IT left_ch_it = &left_ch;
343 C_OUTLINE_IT right_ch_it = &right_ch;
345 C_OUTLINE_IT child_it = srcline->child();
347 srcbox = srcline->bounding_box();
348 if (srcbox.left() + srcbox.right() <= chop_coord * 2 &&
349 srcbox.right() < chop_coord + pitch_error) {
352 left_it->add_after_then_move(srcline);
353 }
else if (srcbox.left() + srcbox.right() > chop_coord * 2 &&
354 srcbox.left() > chop_coord - pitch_error) {
357 right_it->add_before_stay_put(srcline);
360 if (fixed_chop_coutline(srcline, chop_coord, pitch_error, &left_frags, &right_frags)) {
361 for (child_it.mark_cycle_pt(); !child_it.cycled_list(); child_it.forward()) {
362 child = child_it.extract();
363 srcbox =
child->bounding_box();
364 if (srcbox.right() < chop_coord) {
366 left_ch_it.add_after_then_move(
child);
367 }
else if (srcbox.left() > chop_coord) {
369 right_ch_it.add_after_then_move(
child);
373 if (fixed_chop_coutline(
child, chop_coord, 0.0f, &left_frags, &right_frags)) {
376 if (srcbox.left() + srcbox.right() <= chop_coord * 2) {
377 left_ch_it.add_after_then_move(
child);
379 right_ch_it.add_after_then_move(
child);
384 close_chopped_cfragments(&left_frags, &left_ch, pitch_error, left_it);
385 close_chopped_cfragments(&right_frags, &right_ch, pitch_error, right_it);
391 if (srcbox.left() + srcbox.right() <= chop_coord * 2) {
392 left_it->add_after_then_move(srcline);
394 right_it->add_before_stay_put(srcline);
408static bool fixed_chop_coutline(
412 C_OUTLINE_FRAG_LIST *left_frags,
413 C_OUTLINE_FRAG_LIST *right_frags
425 int16_t first_index = 0;
428 length = srcline->pathlength();
429 pos = srcline->start_pos();
433 for (stepindex = 0; stepindex < length; stepindex++) {
434 if (pos.x() < left_edge) {
436 tail_index = stepindex;
439 pos += srcline->step(stepindex);
441 if (left_edge >= chop_coord - pitch_error) {
445 startindex = tail_index;
447 head_index = tail_index;
451 tail_pos += srcline->step(tail_index);
453 if (tail_index == length) {
456 }
while (tail_pos.x() != chop_coord && tail_index != startindex);
457 if (tail_index == startindex) {
466 save_chop_cfragment(head_index, head_pos, tail_index, tail_pos, srcline, left_frags);
468 first_index = tail_index;
469 first_pos = tail_pos;
472 while (srcline->step(tail_index).x() == 0) {
473 tail_pos += srcline->step(tail_index);
475 if (tail_index == length) {
479 head_index = tail_index;
481 while (srcline->step(tail_index).x() > 0) {
483 tail_pos += srcline->step(tail_index);
485 if (tail_index == length) {
488 }
while (tail_pos.x() != chop_coord);
490 save_chop_cfragment(head_index, head_pos, tail_index, tail_pos, srcline, right_frags);
491 while (srcline->step(tail_index).x() == 0) {
492 tail_pos += srcline->step(tail_index);
494 if (tail_index == length) {
498 head_index = tail_index;
501 }
while (tail_index != startindex);
502 save_chop_cfragment(head_index, head_pos, first_index, first_pos, srcline, left_frags);
512static void save_chop_cfragment(
518 C_OUTLINE_FRAG_LIST *frags
522 C_OUTLINE_FRAG *head;
523 C_OUTLINE_FRAG *tail;
528 stepcount = tail_index - head_index;
530 stepcount += srcline->pathlength();
532 jump = tail_pos.y() - head_pos.y();
536 if (jump == stepcount) {
539 tail_y = tail_pos.y();
540 head =
new C_OUTLINE_FRAG(head_pos, tail_pos, srcline, head_index, tail_index);
541 tail =
new C_OUTLINE_FRAG(head, tail_y);
542 head->other_end = tail;
543 add_frag_to_list(head, frags);
544 add_frag_to_list(tail, frags);
557 int16_t start_index, int16_t end_index) {
567 if (end_index > start_index) {
568 for (
int i = start_index;
i < end_index; ++
i) {
574 for (;
i < len; ++
i) {
578 for (;
i < end_index + len; ++
i) {
605static void add_frag_to_list(
607 C_OUTLINE_FRAG_LIST *frags
610 C_OUTLINE_FRAG_IT frag_it = frags;
612 if (!frags->empty()) {
613 for (frag_it.mark_cycle_pt(); !frag_it.cycled_list(); frag_it.forward()) {
614 if (frag_it.data()->ycoord > frag->
ycoord ||
616 frag_it.add_before_then_move(frag);
621 frag_it.add_to_end(frag);
631static void close_chopped_cfragments(
632 C_OUTLINE_FRAG_LIST *frags,
633 C_OUTLINE_LIST *children,
635 C_OUTLINE_IT *dest_it
638 C_OUTLINE_FRAG_IT frag_it = frags;
639 C_OUTLINE_FRAG *bottom_frag;
640 C_OUTLINE_FRAG *top_frag;
643 C_OUTLINE_IT child_it = children;
644 C_OUTLINE_IT olchild_it;
646 while (!frag_it.empty()) {
647 frag_it.move_to_first();
649 bottom_frag = frag_it.extract();
651 top_frag = frag_it.data();
652 if ((bottom_frag->steps ==
nullptr && top_frag->steps ==
nullptr) ||
653 (bottom_frag->steps !=
nullptr && top_frag->steps !=
nullptr)) {
654 if (frag_it.data_relative(1)->ycoord == top_frag->ycoord) {
658 top_frag = frag_it.extract();
659 if (top_frag->other_end != bottom_frag) {
660 outline = join_chopped_fragments(bottom_frag, top_frag);
663 outline = join_chopped_fragments(bottom_frag, top_frag);
664 if (outline !=
nullptr) {
665 olchild_it.set_to_list(outline->child());
666 for (child_it.mark_cycle_pt(); !child_it.cycled_list(); child_it.forward()) {
667 child = child_it.data();
668 if (*
child < *outline) {
669 olchild_it.add_to_end(child_it.extract());
672 if (outline->bounding_box().width() > pitch_error) {
673 dest_it->add_after_then_move(outline);
680 while (!child_it.empty()) {
681 dest_it->add_after_then_move(child_it.extract());
693static C_OUTLINE *join_chopped_fragments(
694 C_OUTLINE_FRAG *bottom,
699 if (bottom->other_end == top) {
700 if (bottom->steps ==
nullptr) {
701 outline = top->close();
703 outline = bottom->close();
709 if (bottom->steps ==
nullptr) {
711 join_segments(bottom->other_end, top);
714 join_segments(top->other_end, bottom);
716 top->other_end->other_end = bottom->other_end;
717 bottom->other_end->other_end = top->other_end;
730static void join_segments(
731 C_OUTLINE_FRAG *bottom,
740 fake_count = top->start.y() - bottom->end.y();
741 if (fake_count < 0) {
742 fake_count = -fake_count;
748 stepcount = bottom->stepcount + fake_count + top->stepcount;
749 steps =
new DIR128[stepcount];
750 memmove(steps, bottom->steps, bottom->stepcount);
751 memset(steps + bottom->stepcount, fake_step.get_dir(), fake_count);
752 memmove(steps + bottom->stepcount + fake_count, top->steps, top->stepcount);
753 delete[] bottom->steps;
754 bottom->steps = steps;
755 bottom->stepcount = stepcount;
756 bottom->end = top->end;
757 bottom->other_end->end = top->end;
768 int32_t new_stepcount;
774 if (fake_count < 0) {
775 fake_count = -fake_count;
785 new_steps =
new DIR128[new_stepcount];
#define INT_VAR(name, val, comment)
@ W_DONT_CHOP
fixed pitch chopped
@ W_REP_CHAR
repeated character
int textord_fp_chop_error
void tprintf(const char *format,...)
void split_to_blob(BLOBNBOX *blob, int16_t chop_coord, float pitch_error, C_OUTLINE_LIST *left_coutlines, C_OUTLINE_LIST *right_coutlines)
ROW * fixed_pitch_words(TO_ROW *row, FCOORD rotation)
void plot_row_cells(ScrollView *win, ScrollView::Color colour, TO_ROW *row, float xshift, ICOORDELT_LIST *cells)
bool textord_show_page_cuts
ICOORDELT_LIST char_cells
BLOBNBOX_LIST * blob_list()
int32_t pathlength() const
DIR128 step_dir(int index) const
static const int kMaxOutlineLength
void recalc_bounding_box()
TDimension y() const
access_function
TDimension x() const
access function
void set_flag(WERD_FLAGS mask, bool value)
TBOX bounding_box() const
C_OUTLINE_FRAG & operator=(const C_OUTLINE_FRAG &src)
C_OUTLINE_FRAG * other_end