📄 fpchop.cpp
字号:
/********************************************************************** * File: fpchop.cpp (Formerly fp_chop.c) * Description: Code to chop fixed pitch text into character cells. * Author: Ray Smith * Created: Thu Sep 16 11:14:15 BST 1993 * * (C) Copyright 1993, Hewlett-Packard Ltd. ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** http://www.apache.org/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. * **********************************************************************/#include "mfcpch.h"#ifdef __UNIX__#include <assert.h>#endif#include "stderr.h"#include "blobbox.h"#include "lmedsq.h"#include "statistc.h"#include "drawtord.h"#include "tovars.h"#include "topitch.h"#include "fpchop.h"#include "notdll.h"#define EXTERNEXTERN INT_VAR (textord_fp_chop_error, 2,"Max allowed bending of chop cells");EXTERN double_VAR (textord_fp_chop_snap, 0.5,"Max distance of chop pt from vertex");ELISTIZE (OUTLINE_FRAG) ELISTIZE (C_OUTLINE_FRAG)//#undef ASSERT_HOST//#define ASSERT_HOST(x) if (!(x)) AfxMessageBox(#x);/********************************************************************** * fixed_pitch_words * * Make a ROW from a fixed pitch TO_ROW. **********************************************************************/ROW *fixed_pitch_words( //find lines TO_ROW *row, //row to do FCOORD rotation //for drawing ) { BOOL8 bol; //start of line UINT8 blanks; //in front of word UINT8 new_blanks; //blanks in empty cell INT16 chop_coord; //chop boundary INT16 prev_chop_coord; //start of cell INT16 rep_left; //left edge of rep word ROW *real_row; //output row OUTLINE_LIST left_outlines; //in current blob OUTLINE_LIST right_outlines; //for next blob C_OUTLINE_LIST left_coutlines; C_OUTLINE_LIST right_coutlines; PBLOB_LIST blobs; //blobs in word C_BLOB_LIST cblobs; PBLOB_IT blob_it = &blobs; //iterator C_BLOB_IT cblob_it = &cblobs; WERD_LIST words; WERD_IT word_it = &words; //new words //repeated blobs WERD_IT rep_it = &row->rep_words; WERD *word; //new word INT32 xstarts[2]; //row ends double coeffs[3]; //quadratic INT32 prev_x; //end of prev blob //iterator BLOBNBOX_IT box_it = row->blob_list (); //boundaries ICOORDELT_IT cell_it = &row->char_cells;#ifndef GRAPHICS_DISABLED if (textord_show_page_cuts && to_win != NO_WINDOW) { plot_row_cells (to_win, RED, row, 0, &row->char_cells); }#endif prev_x = -MAX_INT16; bol = TRUE; blanks = 0; if (rep_it.empty ()) rep_left = MAX_INT16; else rep_left = rep_it.data ()->bounding_box ().left (); if (box_it.empty ()) return NULL; //empty row xstarts[0] = box_it.data ()->bounding_box ().left (); if (rep_left < xstarts[0]) { xstarts[0] = rep_left; } if (cell_it.empty () || row->char_cells.singleton ()) { tprintf ("Row without enough char cells!\n"); tprintf ("Leftmost blob is at (%d,%d)\n", box_it.data ()->bounding_box ().left (), box_it.data ()->bounding_box ().bottom ()); return NULL; } ASSERT_HOST (!cell_it.empty () && !row->char_cells.singleton ()); prev_chop_coord = cell_it.data ()->x (); word = NULL; while (rep_left < cell_it.data ()->x ()) { word = add_repeated_word (&rep_it, rep_left, prev_chop_coord, blanks, row->fixed_pitch, &word_it); } cell_it.mark_cycle_pt (); if (prev_chop_coord >= cell_it.data ()->x ()) cell_it.forward (); for (; !cell_it.cycled_list (); cell_it.forward ()) { chop_coord = cell_it.data ()->x (); while (!box_it.empty () && box_it.data ()->bounding_box ().left () <= chop_coord) { if (box_it.data ()->bounding_box ().right () > prev_x) prev_x = box_it.data ()->bounding_box ().right (); split_to_blob (box_it.extract (), chop_coord, textord_fp_chop_error + 0.5f, &left_outlines, &left_coutlines, &right_outlines, &right_coutlines); box_it.forward (); while (!box_it.empty () && box_it.data ()->blob () == NULL && box_it.data ()->cblob () == NULL) { delete box_it.extract (); box_it.forward (); } } if ((!right_outlines.empty () || !right_coutlines.empty ()) && left_outlines.empty () && left_coutlines.empty ()) split_to_blob (NULL, chop_coord, textord_fp_chop_error + 0.5f, &left_outlines, &left_coutlines, &right_outlines, &right_coutlines); if (!left_outlines.empty ()) blob_it.add_after_then_move (new PBLOB (&left_outlines)); else if (!left_coutlines.empty ()) cblob_it.add_after_then_move (new C_BLOB (&left_coutlines)); else { if (rep_left < chop_coord) { if (rep_left > prev_chop_coord) new_blanks = (UINT8) floor ((rep_left - prev_chop_coord) / row->fixed_pitch + 0.5); else new_blanks = 0; } else { if (chop_coord > prev_chop_coord) new_blanks = (UINT8) floor ((chop_coord - prev_chop_coord) / row->fixed_pitch + 0.5); else new_blanks = 0; } if (!blob_it.empty () || !cblob_it.empty ()) { if (blanks < 1 && word != NULL && !word->flag (W_REP_CHAR)) blanks = 1; if (!blob_it.empty ()) { //make real word word = new WERD (&blobs, blanks, NULL); blob_it.set_to_list (&blobs); } else { word = new WERD (&cblobs, blanks, NULL); cblob_it.set_to_list (&cblobs); } word->set_flag (W_DONT_CHOP, TRUE); word_it.add_after_then_move (word); if (bol) { word->set_flag (W_BOL, TRUE); bol = FALSE; } blanks = new_blanks; } else blanks += new_blanks; while (rep_left < chop_coord) { word = add_repeated_word (&rep_it, rep_left, prev_chop_coord, blanks, row->fixed_pitch, &word_it); } } if (prev_chop_coord < chop_coord) prev_chop_coord = chop_coord; } if (!blob_it.empty () || !cblob_it.empty ()) { if (!blob_it.empty ()) //last word on line word = new WERD (&blobs, blanks, NULL); else word = new WERD (&cblobs, blanks, NULL); word->set_flag (W_DONT_CHOP, TRUE); word_it.add_after_then_move (word); if (bol) word->set_flag (W_BOL, TRUE); } ASSERT_HOST (word != NULL); while (!rep_it.empty ()) { add_repeated_word (&rep_it, rep_left, prev_chop_coord, blanks, row->fixed_pitch, &word_it); } //at end of line word_it.data ()->set_flag (W_EOL, TRUE); if (prev_chop_coord > prev_x) prev_x = prev_chop_coord; xstarts[1] = prev_x + 1; coeffs[0] = 0; coeffs[1] = row->line_m (); coeffs[2] = row->line_c (); real_row = new ROW (row, (INT16) row->kern_size, (INT16) row->space_size); word_it.set_to_list (real_row->word_list ()); //put words in row word_it.add_list_after (&words); real_row->recalc_bounding_box (); return real_row;}/********************************************************************** * add_repeated_word * * Add repeated word into the row at the given point. **********************************************************************/WERD *add_repeated_word( //move repeated word WERD_IT *rep_it, //repeated words INT16 &rep_left, //left edge of word INT16 &prev_chop_coord, //previous word end UINT8 &blanks, //no of blanks float pitch, //char cell size WERD_IT *word_it //list of words ) { WERD *word; //word to move INT16 new_blanks; //extra blanks if (rep_left > prev_chop_coord) { new_blanks = (UINT8) floor ((rep_left - prev_chop_coord) / pitch + 0.5); blanks += new_blanks; } word = rep_it->extract (); prev_chop_coord = word->bounding_box ().right (); word_it->add_after_then_move (word); word->set_blanks (blanks); rep_it->forward (); if (rep_it->empty ()) rep_left = MAX_INT16; else rep_left = rep_it->data ()->bounding_box ().left (); blanks = 0; return word;}/********************************************************************** * split_to_blob * * Split a BLOBNBOX across a vertical chop line and put the pieces * into a left outline list and a right outline list. **********************************************************************/void split_to_blob( //split the blob BLOBNBOX *blob, //blob to split INT16 chop_coord, //place to chop float pitch_error, //allowed deviation OUTLINE_LIST *left_outlines, //left half of chop C_OUTLINE_LIST *left_coutlines, //for cblobs OUTLINE_LIST *right_outlines, //right half of chop C_OUTLINE_LIST *right_coutlines) { PBLOB *real_blob; //blob to chop C_BLOB *real_cblob; //cblob to chop if (blob != NULL) { real_blob = blob->blob (); real_cblob = blob->cblob (); } else { real_blob = NULL; real_cblob = NULL; } if (!right_outlines->empty () || real_blob != NULL) fixed_chop_blob(real_blob, chop_coord, pitch_error, left_outlines, right_outlines); else if (!right_coutlines->empty () || real_cblob != NULL) fixed_chop_cblob(real_cblob, chop_coord, pitch_error, left_coutlines, right_coutlines); if (blob != NULL) delete blob; //free it}/********************************************************************** * fixed_chop_blob * * Chop the given blob (if any) and the existing right outlines to * produce a list of outlines left of the chop point and more to the right. **********************************************************************/void fixed_chop_blob( //split the blob PBLOB *blob, //blob to split INT16 chop_coord, //place to chop float pitch_error, //allowed deviation OUTLINE_LIST *left_outlines, //left half of chop OUTLINE_LIST *right_outlines //right half of chop ) { OUTLINE *old_right; //already there OUTLINE_LIST new_outlines; //new right ones //ouput iterator OUTLINE_IT left_it = left_outlines; //in/out iterator OUTLINE_IT right_it = right_outlines; OUTLINE_IT new_it = &new_outlines; OUTLINE_IT blob_it; //outlines in blob if (!right_it.empty ()) { while (!right_it.empty ()) { old_right = right_it.extract (); right_it.forward (); fixed_split_outline(old_right, chop_coord, pitch_error, &left_it, &new_it); } right_it.add_list_before (&new_outlines); } if (blob != NULL) { blob_it.set_to_list (blob->out_list ()); for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) fixed_split_outline (blob_it.extract (), chop_coord, pitch_error, &left_it, &right_it); delete blob; }}/********************************************************************** * fixed_split_outline * * Chop the given outline (if necessary) placing the fragments which * fall either side of the chop line into the appropriate list. **********************************************************************/void fixed_split_outline( //chop the outline OUTLINE *srcline, //source outline INT16 chop_coord, //place to chop float pitch_error, //allowed deviation OUTLINE_IT *left_it, //left half of chop OUTLINE_IT *right_it //right half of chop ) { OUTLINE *child; //child outline BOX srcbox; //box of outline OUTLINE_LIST left_ch; //left children OUTLINE_LIST right_ch; //right children OUTLINE_FRAG_LIST left_frags; //chopped fragments OUTLINE_FRAG_LIST right_frags;; OUTLINE_IT left_ch_it = &left_ch; //for whole children OUTLINE_IT right_ch_it = &right_ch; //for holes OUTLINE_IT child_it = srcline->child (); srcbox = srcline->bounding_box (); //left of line if (srcbox.left () + srcbox.right () <= chop_coord * 2 //and not far over && srcbox.right () < chop_coord + pitch_error) //stick whole in left left_it->add_after_then_move (srcline); else if (srcbox.left () + srcbox.right () > chop_coord * 2 && srcbox.left () > chop_coord - pitch_error) //stick whole in right right_it->add_before_stay_put (srcline); else { //needs real chopping if (fixed_chop_outline (srcline, chop_coord, pitch_error, &left_frags, &right_frags)) { for (child_it.mark_cycle_pt (); !child_it.cycled_list (); child_it.forward ()) { child = child_it.extract (); srcbox = child->bounding_box (); if (srcbox.right () < chop_coord) left_ch_it.add_after_then_move (child); else if (srcbox.left () > chop_coord) right_ch_it.add_after_then_move (child); else { if (fixed_chop_outline (child, chop_coord, pitch_error, &left_frags, &right_frags)) delete child; else { if (srcbox.left () + srcbox.right () <= chop_coord * 2) left_ch_it.add_after_then_move (child); else right_ch_it.add_after_then_move (child); } } } close_chopped_fragments(&left_frags, &left_ch, left_it); close_chopped_fragments(&right_frags, &right_ch, right_it); ASSERT_HOST (left_ch.empty () && right_ch.empty ()); //no children left
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -