You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/kword/pdf/misc.cpp

435 lines
14 KiB

/*
* Copyright (c) 2002-2003 Nicolas HADACEK (hadacek@kde.org)
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "misc.h"
#include <math.h>
#include <tqfontmetrics.h>
#include <tqfontdatabase.h>
#include <tdeglobal.h>
#include <kdebug.h>
#include "Link.h"
#include "Catalog.h"
#include "GfxState.h"
#include "GfxFont.h"
namespace PDFImport
{
TQColor toColor(GfxRGB &rgb)
{
return TQColor(tqRound(rgb.r*255), tqRound(rgb.g*255), tqRound(rgb.b*255));
}
//-----------------------------------------------------------------------------
bool DRect::operator ==(const DRect &r) const
{
return ( equal(_top, r._top) && equal(_bottom, r._bottom)
&& equal(_left, r._left) && equal(_right, r._right) );
}
bool DRect::isInside(const DRect &r, double percent) const
{
return ( more(r._top, _top, percent) && less(r._bottom, _bottom, percent)
&& more(r._left, _left, percent)
&& less(r._right, _right, percent) );
}
void DRect::unite(const DRect &r)
{
if ( !r.isValid() ) return;
if ( !isValid() ) {
*this = r;
return;
}
_left = kMin(_left, r._left);
_right = kMax(_right, r._right);
_top = kMin(_top, r._top);
_bottom = kMax(_bottom, r._bottom);
}
TQString DRect::toString() const
{
if ( !isValid() ) return "invalid rect";
return TQString("left=%1 right=%2 top=%3 bottom=%4").arg(_left).arg(_right)
.arg(_top).arg(_bottom);
}
bool DPath::isRectangle() const
{
if ( size()!=5 ) return false;
if ( !equal(at(0).x, at(3).x) || !equal(at(0).x, at(4).x) ) return false;
if ( !equal(at(0).y, at(1).y) || !equal(at(0).y, at(4).y) ) return false;
if ( !equal(at(1).x, at(2).x) || !equal(at(2).y, at(3).y) ) return false;
return true;
}
DRect DPath::boundingRect() const
{
if ( size()==0 ) return DRect();
DRect r(at(0).x, at(0).x, at(0).y, at(0).y);
for (uint i=1; i<size(); i++) {
r.setTop( kMin(r.top(), at(i).y) );
r.setBottom( kMax(r.bottom(), at(i).y) );
r.setLeft( kMin(r.left(), at(i).x) );
r.setRight( kMax(r.right(), at(i).x) );
}
return r;
}
//-----------------------------------------------------------------------------
TQDict<Font::Data> *Font::_dict = 0;
const char *Font::FAMILY_DATA[Nb_Family] = {
"Times", "Helvetica", "Courier", "Symbol"
};
void Font::init()
{
Q_ASSERT( _dict==0 );
_dict = new TQDict<Data>(100, false); // case insensitive
_dict->setAutoDelete(true);
}
void Font::cleanup()
{
delete _dict;
_dict = 0;
}
Font::Font()
: _pointSize(12), _color(TQt::black)
{
init("times-roman");
}
Font::Font(const GfxState *state, double size)
{
if ( size<1 ) kdDebug(30516) << "very small font size=" << size << endl;
_pointSize = tqRound(size);
GfxRGB rgb;
state->getFillRGB(&rgb);
_color = toColor(rgb);
GfxFont *font = state->getFont();
GString *gname = (font ? font->getName() : 0);
TQString name = (gname ? gname->getCString() : 0);
// kdDebug(30516) << "font: " << name << endl;
name = name.section('+', 1, 1).lower();
if ( name.isEmpty() ) name = "##dummy"; // dummy name
init(name);
}
struct KnownData {
const char *name;
FontFamily family;
FontStyle style;
bool latex;
};
static const KnownData KNOWN_DATA[] = {
// standard XPDF fonts (the order is important for finding !)
{ "times-roman", Times, Regular, false },
{ "times-bolditalic", Times, BoldItalic, false },
{ "times-bold", Times, Bold, false },
{ "times-italic", Times, Italic, false },
{ "helvetica-bolditalic", Helvetica, BoldItalic, false },
{ "helvetica-bold", Helvetica, Bold, false },
{ "helvetica-italic", Times, Italic, false },
{ "helvetica", Helvetica, Regular, false },
{ "courier-bolditalic", Courier, BoldItalic, false },
{ "courier-bold", Courier, Bold, false },
{ "courier-italic", Courier, Italic, false },
{ "courier", Courier, Regular, false },
{ "symbol", Symbol, Regular, false },
// some latex fonts
{ "cmr", Times, Regular, true },
{ "cmbx", Times, Bold, true },
{ "cmcsc", Times, Regular, true }, // small caps
{ "cmmi", Times, Italic, true },
{ "cmtt", Courier, Regular, true },
{ "cmsy", Symbol, Regular, true },
{ "msbm", Times, Regular, true }, // math caps
{ 0, Nb_Family, Regular, false }
};
void Font::init(const TQString &n)
{
// check if font already parsed
_data = _dict->find(n);
if ( _data==0 ) {
// kdDebug(30516) << "font " << n << endl;
TQString name = n;
name.replace("oblique", "italic");
// check if known font
_data = new Data;
uint i = 0;
while ( KNOWN_DATA[i].name!=0 ) {
if ( name.find(KNOWN_DATA[i].name)!=-1 ) {
// kdDebug(30516) << "found " << KNOWN_DATA[i].name
// << " " << isBold(KNOWN_DATA[i].style) << endl;
_data->family = FAMILY_DATA[KNOWN_DATA[i].family];
_data->style = KNOWN_DATA[i].style;
_data->latex = KNOWN_DATA[i].latex;
break;
}
i++;
}
if ( _data->family.isEmpty() ) { // let's try harder
// simple heuristic
kdDebug(30516) << "unknown font : " << n << endl;
if ( name.find("times")!=-1 )
_data->family = FAMILY_DATA[Times];
else if ( name.find("helvetica")!=-1 )
_data->family = FAMILY_DATA[Helvetica];
else if ( name.find("courier")!=-1 )
_data->family = FAMILY_DATA[Courier];
else if ( name.find("symbol")!=-1 )
_data->family = FAMILY_DATA[Symbol];
else { // with TQt
TQFontDatabase fdb;
TQStringList list = fdb.families();
list = list.grep(name, false);
if ( !list.isEmpty() ) {
_data->family = list[0];
kdDebug(30516) << "in TQt database as " << list[0] << endl;
}
else {
kdDebug(30516) << "really unknown font !" << endl;
_data->family = name;
}
}
bool italic = ( name.find("italic")!=-1 );
bool bold = ( name.find("bold")!=-1 );
_data->style = toStyle(bold, italic);
_data->latex = false;
}
_dict->insert(name, _data);
}
// check if TQFont already created
if ( !_data->height.contains(_pointSize) ) {
TQFont font(_data->family, _pointSize,
(isBold(_data->style) ? TQFont::Bold : TQFont::Normal),
isItalic(_data->style));
TQFontMetrics fm(font);
_data->height.insert(_pointSize, fm.height());
}
}
bool Font::operator ==(const Font &font) const
{
if ( _pointSize!=font._pointSize ) return false;
if ( _data->family!=font._data->family ) return false;
if ( _data->style!=font._data->style ) return false;
// if ( _underline!=font._underline ) return false;
// if ( _strikeOut!=font._strikeOut ) return false;
if ( _color!=font._color ) return false;
return true;
}
bool Font::format(TQDomDocument &doc, TQDomElement &f,
uint pos, uint len, bool all) const
{
f.setAttribute("id", 1);
if (!all) f.setAttribute("pos", pos);
if (!all) f.setAttribute("len", len);
TQDomElement element;
Font def;
if ( all || _data->family!=def._data->family ) {
element = doc.createElement("FONT");
element.setAttribute("name", _data->family);
f.appendChild(element);
}
if ( all || _pointSize!=def._pointSize ) {
element = doc.createElement("SIZE");
element.setAttribute("value", _pointSize);
f.appendChild(element);
}
if ( all || isItalic(_data->style)!=isItalic(def._data->style) ) {
element = doc.createElement("ITALIC");
element.setAttribute("value", (isItalic(_data->style) ? 1 : 0));
f.appendChild(element);
}
if ( all || isBold(_data->style)!=isBold(def._data->style) ) {
element = doc.createElement("WEIGHT");
element.setAttribute("value",
(isBold(_data->style) ? TQFont::Bold : TQFont::Normal));
f.appendChild(element);
}
// if ( all || _underline!=def._underline ) {
// element = doc.createElement("UNDERLINE");
// element.setAttribute("value", (_underline ? 1 : 0));
// f.appendChild(element);
// }
// if ( all || _strikeOut!=def._strikeOut ) {
// element = doc.createElement("STRIKEOUT");
// element.setAttribute("value", (_strikeOut ? 1 : 0));
// f.appendChild(element);
// }
if (all) {
element = doc.createElement("VERTALIGN");
element.setAttribute("value", 0);
f.appendChild(element);
}
if ( all || _color!=def._color ) {
element = doc.createElement("COLOR");
element.setAttribute("red", _color.red());
element.setAttribute("green", _color.green());
element.setAttribute("blue", _color.blue());
f.appendChild(element);
}
if (all) { // #### FIXME
element = doc.createElement("TEXTBACKGROUNDCOLOR");
element.setAttribute("red", 255);
element.setAttribute("green",255);
element.setAttribute("blue", 255);
f.appendChild(element);
}
return f.hasChildNodes();
}
void Font::setFamily(FontFamily f)
{
int k = -1;
uint i=0;
while ( KNOWN_DATA[i].name!=0 ) {
if ( KNOWN_DATA[i].family==f ) {
if ( KNOWN_DATA[i].style==_data->style ) {
k = i;
break;
}
if ( k==-1 ) k = i;
}
i++;
}
if ( k==-1 ) k = 0;
init(KNOWN_DATA[k].name);
}
//-----------------------------------------------------------------------------
Link::Link(const DRect &rect, LinkAction &action, Catalog &catalog)
: _rect(rect)
{
switch ( action.getKind() ) {
case actionGoTo: {
LinkGoTo &lgoto = static_cast<LinkGoTo &>(action);
LinkDest *dest = (lgoto.getDest() ? lgoto.getDest()->copy()
: catalog.findDest( lgoto.getNamedDest() ));
int page = 1;
if (dest) {
if ( dest->isPageRef() ) {
Ref pageref = dest->getPageRef();
page = catalog.findPage(pageref.num, pageref.gen);
} else page = dest->getPageNum();
delete dest;
}
_href = TQString("bkm://") + pageLinkName(page);
// kdDebug(30516) << "link to page " << page << endl;
break;
}
case actionGoToR: {
LinkGoToR &lgotor = static_cast<LinkGoToR &>(action);
_href = "file://";
if ( lgotor.getFileName() )
_href += lgotor.getFileName()->getCString();
int page = 1;
if ( lgotor.getDest() ) {
LinkDest *dest = lgotor.getDest()->copy();
if ( !dest->isPageRef() ) page = dest->getPageNum();
delete dest;
}
kdDebug(30516) << "link to filename \"" << _href << "\" (page "
<< page << ")" <<endl;
break;
}
case actionLaunch: {
LinkLaunch &llaunch = static_cast<LinkLaunch &>(action);
_href = "file://";
if ( llaunch.getFileName() )
_href += llaunch.getFileName()->getCString();
kdDebug(30516) << "link to launch/open \"" << _href << "\"" << endl;
break;
}
case actionURI: {
LinkURI &luri = static_cast<LinkURI &>(action);
if ( luri.getURI() ) _href = luri.getURI()->getCString();
kdDebug(30516) << "link to URI \"" << _href << "\"" << endl;
break;
}
case actionMovie:
case actionNamed:
case actionUnknown:
kdDebug(30516) << "unsupported link=" << action.getKind() << endl;
break;
}
}
void Link::format(TQDomDocument &doc, TQDomElement &f, uint pos,
const TQString &text) const
{
f.setAttribute("id", 4);
f.setAttribute("pos", pos);
f.setAttribute("len", 1);
TQDomElement v = doc.createElement("VARIABLE");
TQDomElement element = doc.createElement("TYPE");
element.setAttribute("type", 9);
element.setAttribute("key", "STRING");
element.setAttribute("text", text);
v.appendChild(element);
element = doc.createElement("LINK");
element.setAttribute("linkName", text);
element.setAttribute("hrefName", _href);
v.appendChild(element);
f.appendChild(v);
}
TQString Link::pageLinkName(uint i)
{
return TQString("page") + TQString::number(i);
}
} // namespace