diff options
author | etheisen <etheisen@cvs.openbsd.org> | 1996-09-14 19:02:02 +0000 |
---|---|---|
committer | etheisen <etheisen@cvs.openbsd.org> | 1996-09-14 19:02:02 +0000 |
commit | 6a4f3d0fd940c1e7052ddf23907f0e297dc42f4b (patch) | |
tree | 712fd665d6b150ef04906975a7493d87d38a1a8a /gnu/usr.bin/groff/libdriver/printer.cc | |
parent | 9cf27152dae9dbf80b167732c78c47baee90ddc5 (diff) |
Third time because import sucks.
Diffstat (limited to 'gnu/usr.bin/groff/libdriver/printer.cc')
-rw-r--r-- | gnu/usr.bin/groff/libdriver/printer.cc | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/gnu/usr.bin/groff/libdriver/printer.cc b/gnu/usr.bin/groff/libdriver/printer.cc new file mode 100644 index 00000000000..e7547deeebb --- /dev/null +++ b/gnu/usr.bin/groff/libdriver/printer.cc @@ -0,0 +1,241 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "driver.h" + +printer *pr = 0; + +font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) +: p(f), next(fp) +{ +} + +printer::printer() +: font_table(0), nfonts(0), font_list(0) +{ +} + +printer::~printer() +{ + a_delete font_table; + while (font_list) { + font_pointer_list *tem = font_list; + font_list = font_list->next; + delete tem->p; + delete tem; + } + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); +} + +void printer::load_font(int n, const char *nm) +{ + assert(n >= 0); + if (n >= nfonts) { + if (nfonts == 0) { + nfonts = 10; + if (nfonts <= n) + nfonts = n + 1; + font_table = new font *[nfonts]; + for (int i = 0; i < nfonts; i++) + font_table[i] = 0; + } + else { + font **old_font_table = font_table; + int old_nfonts = nfonts; + nfonts *= 2; + if (n >= nfonts) + nfonts = n + 1; + font_table = new font *[nfonts]; + int i; + for (i = 0; i < old_nfonts; i++) + font_table[i] = old_font_table[i]; + for (i = old_nfonts; i < nfonts; i++) + font_table[i] = 0; + a_delete old_font_table; + } + } + font *f = find_font(nm); + font_table[n] = f; +} + +font *printer::find_font(const char *nm) +{ + for (font_pointer_list *p = font_list; p; p = p->next) + if (strcmp(p->p->get_name(), nm) == 0) + return p->p; + font *f = make_font(nm); + if (!f) + fatal("sorry, I can't continue"); + font_list = new font_pointer_list(f, font_list); + return f; +} + +font *printer::make_font(const char *nm) +{ + return font::load_font(nm); +} + +void printer::end_of_line() +{ +} + +void printer::special(char *, const environment *) +{ +} + +void printer::draw(int, int *, int, const environment *) +{ +} + +void printer::set_ascii_char(unsigned char c, const environment *env, + int *widthp) +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + set_special_char(buf, env, widthp); +} + +void printer::set_special_char(const char *nm, const environment *env, + int *widthp) +{ + int i = font::name_to_index(nm); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + if (nm[0] != '\0' && nm[1] == '\0') + error("font `%1' does not contain ascii character `%2'", + f->get_name(), + nm[0]); + else + error("font `%1' does not contain special character `%2'", + f->get_name(), + nm); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w); +} + +void printer::set_numbered_char(int num, const environment *env, int *widthp) +{ + int i = font::number_to_index(num); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + error("font `%1' does not contain numbered character %2", + f->get_name(), + num); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w); +} + +// This utility function adjusts the specified center of the +// arc so that it is equidistant between the specified start +// and end points. (p[0], p[1]) is a vector from the current +// point to the center; (p[2], p[3]) is a vector from the +// center to the end point. If the center can be adjusted, +// a vector from the current point to the adjusted center is +// stored in c[0], c[1] and 1 is returned. Otherwise 0 is +// returned. + +#if 1 +int printer::adjust_arc_center(const int *p, double *c) +{ + // We move the center along a line parallel to the line between + // the specified start point and end point so that the center + // is equidistant between the start and end point. + // It can be proved (using Lagrange multipliers) that this will + // give the point nearest to the specified center that is equidistant + // between the start and end point. + + double x = p[0] + p[2]; // (x, y) is the end point + double y = p[1] + p[3]; + double n = x*x + y*y; + if (n != 0) { + c[0]= double(p[0]); + c[1] = double(p[1]); + double k = .5 - (c[0]*x + c[1]*y)/n; + c[0] += k*x; + c[1] += k*y; + return 1; + } + else + return 0; +} +#else +int printer::adjust_arc_center(const int *p, double *c) +{ + int x = p[0] + p[2]; // (x, y) is the end point + int y = p[1] + p[3]; + // Start at the current point; go in the direction of the specified + // center point until we reach a point that is equidistant between + // the specified starting point and the specified end point. Place + // the center of the arc there. + double n = p[0]*double(x) + p[1]*double(y); + if (n > 0) { + double k = (double(x)*x + double(y)*y)/(2.0*n); + // (cx, cy) is our chosen center + c[0] = k*p[0]; + c[1] = k*p[1]; + return 1; + } + else { + // We would never reach such a point. So instead start at the + // specified end point of the arc. Go towards the specified + // center point until we reach a point that is equidistant between + // the specified start point and specified end point. Place + // the center of the arc there. + n = p[2]*double(x) + p[3]*double(y); + if (n > 0) { + double k = 1 - (double(x)*x + double(y)*y)/(2.0*n); + // (c[0], c[1]) is our chosen center + c[0] = p[0] + k*p[2]; + c[1] = p[1] + k*p[3]; + return 1; + } + else + return 0; + } +} +#endif |