/* drvbase.c : This file is part of pstoedit Basic, driver independent output routines Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz, Wolfgang.Glunz@zfe.siemens.de This program 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 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "drvbase.h" drvbase::drvbase(ostream & theoutStream, bool backendSupportsSubPathes_p, bool backendSupportsCurveto_p, bool backendSupportsMerging_p) : // constructor backendSupportsSubPathes(backendSupportsSubPathes_p), backendSupportsCurveto(backendSupportsCurveto_p), backendSupportsMerging(backendSupportsMerging_p), page_empty (1), outf (theoutStream), scale (1.0), // set some common defaults currentDeviceHeight (792.0 * scale), x_offset (0), y_offset (0), currentPageNumber (1), pathnumber (0), verbose (false), domerge (false) { // init segment info for first segment // all others will be updated with each newsegment verbose = (getenv("PSTOEDITVERBOSE") != 0); if (verbose) { cerr << "verbose mode turned on\n" << endl; } numbers = new float[maxpoints]; // The number stack nextFreeNumber = 0; currentPath = &p1; lastPath = &p2; outputPath = currentPath; if ((numbers == 0) || (p1.path == 0) || (p2.path == 0) ) { cerr << "new failed in drvbase::drvbase " << endl; exit(1); } setCurrentFontName("Courier",1); setCurrentFontFamilyName("Courier"); setCurrentFontWeight("Regular"); setCurrentFontFullName("Courier"); setCurrentFontSize(10); } drvbase::~drvbase() { delete [] numbers; currentPath = 0; lastPath = 0; outputPath = 0; } void drvbase::run(bool merge) { domerge = false; // default if (merge) { if ( backendSupportsMerging ) { domerge = true; } else { cerr << "the selected backend does not support merging, -merge ignored" << endl; } } yylex(); outputPath->clear(); // define past the end path as empty dumpPath(); // dump last path // close page (if no explicit showpage was done) if (!page_empty) { close_page(); } page_empty = 1; } bool drvbase::pathsCanBeMerged(const PathInfo & p1, const PathInfo & p2) { // return 0; // two paths can be merged if one of them is a stroke and the // other a fill AND // all pathelements are the same // cerr << p1.numberOfElementsInPath << " " << p2.numberOfElementsInPath << endl; if (((p1.currentShowType == stroke && p2.currentShowType == fill) || (p2.currentShowType == stroke && p1.currentShowType == fill) ) && (p1.numberOfElementsInPath == p2.numberOfElementsInPath) ) { // cerr << "Pathes seem to be mergeable" << endl; for (unsigned int i = 0; i < p1.numberOfElementsInPath ; i++) { const basedrawingelement *bd1 = p1.path[i]; const basedrawingelement *bd2 = p2.path[i]; // if (! *(p1.path[i]) == *(p2.path[i]) ) return 0; if (! (*bd1 == *bd2) ) return 0; } // cerr << "Pathes are mergeable" << endl; return 1; } else { return 0; } } void drvbase::addNumber(float co) { // printf("Adding %f\n",co); if (nextFreeNumber < maxpoints) { numbers[nextFreeNumber++] = co; // nextFreeNumber always points to the next free number } else { cerr << "Too many numbers on stack. Please increase maxpoints in drvbase.h \n"; exit(1); } } const basedrawingelement & drvbase::pathElement(unsigned int index) const { return *(outputPath->path[index]); } bool operator==(const basedrawingelement & bd1, const basedrawingelement & bd2) { if (bd1.getType() != bd2.getType() ) { return 0; } else { for (unsigned int i = 0; i < bd1.size; i++ ) { if (! (bd1.getPoint(i) == bd2.getPoint(i)) ) return 0; } } return 1; } void drvbase::dumpText(const char * const thetext) { add_to_page(); float y = pop(); float x = pop(); textInfo_.x = x; textInfo_.y = y; textInfo_.thetext = thetext; show_text(textInfo_); } float drvbase::pop() { if (nextFreeNumber > 0) { nextFreeNumber--; return numbers[nextFreeNumber]; // the value we just popped } else { cerr << "Fatal error in drvbase::pop : nextFreeNumber would get < 0" << endl; exit(1); } return 0; // never reached, just to make compiler quiet } void drvbase::setCurrentFontName(const char * const Name,bool is_non_standard_font) { strncpy(textInfo_.currentFontName,Name,maxFontNamesLength); textInfo_.is_non_standard_font = is_non_standard_font; } void drvbase::setCurrentFontFamilyName(const char * const Name) { strncpy(textInfo_.currentFontFamilyName,Name,maxFontNamesLength); } void drvbase::setCurrentFontFullName(const char * const Name) { strncpy(textInfo_.currentFontFullName,Name,maxFontNamesLength); } void drvbase::setCurrentFontWeight(const char * const Name) { strncpy(textInfo_.currentFontWeight,Name,maxFontNamesLength); } void drvbase::setCurrentFontSize(const float Size) { /* cerr << "setting Size to " << Size << endl; */ textInfo_.currentFontSize = Size ; } void drvbase::setCurrentFontAngle(float value) { textInfo_.currentFontAngle = value; } bool drvbase::is_a_rectangle() { #if 0 // TODO, Not yet implemented int dir; /* 1 - up/down (same x) 0 - left/right (same y) */ if (numbersInCurrentSegment() != 10) return 0; /* it might be a rectangle */ if (pNumber(0) == pNumber(2)) { /* same x */ dir = 0; } else if (pNumber(1) == pNumber(3)) { /* same y */ dir = 1; } else { /* no rectangle */ return 0; } for (int i = 0; i < 8; i++, i++) { if (dir == 1) { if (!(pNumber(i + 1) == pNumber(i + 1 + 2))) return 0; dir = 0; } else { if (!(pNumber(i) == pNumber(i + 2))) return 0; dir = 1; } } return 1; #else return 0; #endif } static float Max(float a,float b) { return (a>b ? a : b); } static float Min(float a,float b) { return (a 0 ) { // nothing to do for empty pathes // pathes may be empty due to a merge operation if (verbose) { cerr << "working on"; switch ( currentShowType() ) { case drvbase::stroke: cerr << " stroked "; break; case drvbase::fill: cerr << " filled "; break; case drvbase::eofill: cerr << " eofilled "; break; default: break; } cerr << "path " << currentNr() << " with " << numberOfElementsInPath() << " elements" << endl; } if (numberOfElementsInPath() > 1) { // cannot draw single points add_to_page(); if (isPolygon()) { /* PolyGon */ if (is_a_rectangle()) { { float llx,lly,urx,ury; #if 0 // TODO, Not yet implemented llx = min( min(pNumber(0),pNumber(2)), min(pNumber(4),pNumber(6))); urx = max( max(pNumber(0),pNumber(2)), max(pNumber(4),pNumber(6))); lly = min( min(pNumber(1),pNumber(3)), min(pNumber(5),pNumber(7))); ury = max( max(pNumber(1),pNumber(3)), max(pNumber(5),pNumber(7))); show_rectangle(llx,lly,urx,ury); #endif } } else { show_path(); } } else { /* PolyLine */ show_path(); }; } // cleanup outputPath->clear(); } // swap current and last pointers PathInfo *help = currentPath; currentPath = lastPath; lastPath = help; outputPath = currentPath; } void drvbase::addtopath(basedrawingelement * newelement) { if (newelement) { if (currentPath->numberOfElementsInPath < maxElements) { currentPath->path[currentPath->numberOfElementsInPath] = newelement; #ifdef DEBUG cout << "pathelement " << currentPath->numberOfElementsInPath << " added " << *newelement << endl; #endif currentPath->numberOfElementsInPath++; } else { cerr << "Fatal: number of path elements exceeded. Increase maxElements in drvbase.h" << endl; exit(1); } } else { cerr << "Fatal: newelement is NULL in addtopath " << endl; exit(1); } } void drvbase::PathInfo::clear() { for (unsigned int i = 0 ; i < numberOfElementsInPath; i++ ) { delete path[i]; path[i] = 0; } numberOfElementsInPath = 0; } ostream & operator<<(ostream & out,const basedrawingelement &elem) { out << "type: " << (int) elem.getType() << " params: " ; for (unsigned int i = 0 ; i < elem.size ; i++ ) { out << elem.getPoint(i).x_ << " " << elem.getPoint(i).y_ << " "; } out << endl; return out; } ColorTable::ColorTable(const char * const * defaultColors, const unsigned int numberOfDefaultColors, makeColorNameType makeColorName) : defaultColors_(defaultColors), numberOfDefaultColors_(numberOfDefaultColors), makeColorName_(makeColorName) { for (unsigned int i = 0 ; i< maxcolors; i++) newColors[i] = 0; } ColorTable::~ColorTable() { unsigned int current= 0; while (newColors[current] != 0) { delete [] newColors[current]; current++; } } unsigned int ColorTable::getColorIndex(float r, float g, float b) { // registers a possibly new color and returns the index // under which the color was registered const char * cmp = makeColorName_(r,g,b); for (unsigned int i = 0; i < numberOfDefaultColors_ ; i++ ) { if (strcmp(cmp,defaultColors_[i]) == 0) { return i; } } // look in new colors unsigned int j = 0; for (j = 0; ((j < maxcolors) && (newColors[j] != 0)) ; j++ ) { if (strcmp(cmp,newColors[j]) == 0) { return j+numberOfDefaultColors_; } } // not found so far // j is either maxcolors or the index of the next free entry // add a copy to newColors if (j < maxcolors) { newColors[j] = new char[strlen(cmp) +1]; strcpy(newColors[j],cmp); return j+numberOfDefaultColors_; } else { cerr << "running out of colors" << endl; return 0; } } const char * const ColorTable::getColorString(float r, float g, float b) { return getColorString(getColorIndex(r,g,b)); } bool ColorTable::isKnownColor(float r, float g, float b) const { // Possible improvements: // could return the next free entry as negative number in case // the color is not found. This would make it possible to // use this function in getColorEntry as well, or (better) // make a pure registercolor(index,.....) instead of // getColorEntry. const char * cmp = makeColorName_(r,g,b); for (unsigned int i = 0; i < numberOfDefaultColors_ ; i++ ) { if (strcmp(cmp,defaultColors_[i]) == 0) { return true; } } // look in new colors unsigned int j = 0; for (j = 0; ((j < maxcolors) && (newColors[j] != 0)) ; j++ ) { if (strcmp(cmp,newColors[j]) == 0) { return true; // j+numberOfDefaultColors_; } } // not found so far return false; } const char * const ColorTable::getColorString(unsigned int index) const { return (index < numberOfDefaultColors_) ? defaultColors_[index] : newColors[index - numberOfDefaultColors_]; }