00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "misc.h"
00021
00022 #include <math.h>
00023 #include <qfontmetrics.h>
00024 #include <qfontdatabase.h>
00025 #include <kglobal.h>
00026 #include <kdebug.h>
00027
00028 #include "Link.h"
00029 #include "Catalog.h"
00030 #include "GfxState.h"
00031 #include "GfxFont.h"
00032
00033
00034 namespace PDFImport
00035 {
00036
00037
00038 QColor toColor(GfxRGB &rgb)
00039 {
00040 return QColor(qRound(rgb.r*255), qRound(rgb.g*255), qRound(rgb.b*255));
00041 }
00042
00043
00044 bool DRect::operator ==(const DRect &r) const
00045 {
00046 return ( equal(_top, r._top) && equal(_bottom, r._bottom)
00047 && equal(_left, r._left) && equal(_right, r._right) );
00048 }
00049
00050 bool DRect::isInside(const DRect &r, double percent) const
00051 {
00052 return ( more(r._top, _top, percent) && less(r._bottom, _bottom, percent)
00053 && more(r._left, _left, percent)
00054 && less(r._right, _right, percent) );
00055 }
00056
00057 void DRect::unite(const DRect &r)
00058 {
00059 if ( !r.isValid() ) return;
00060 if ( !isValid() ) {
00061 *this = r;
00062 return;
00063 }
00064 _left = kMin(_left, r._left);
00065 _right = kMax(_right, r._right);
00066 _top = kMin(_top, r._top);
00067 _bottom = kMax(_bottom, r._bottom);
00068 }
00069
00070 QString DRect::toString() const
00071 {
00072 if ( !isValid() ) return "invalid rect";
00073 return QString("left=%1 right=%2 top=%3 bottom=%4").arg(_left).arg(_right)
00074 .arg(_top).arg(_bottom);
00075 }
00076
00077 bool DPath::isRectangle() const
00078 {
00079 if ( size()!=5 ) return false;
00080 if ( !equal(at(0).x, at(3).x) || !equal(at(0).x, at(4).x) ) return false;
00081 if ( !equal(at(0).y, at(1).y) || !equal(at(0).y, at(4).y) ) return false;
00082 if ( !equal(at(1).x, at(2).x) || !equal(at(2).y, at(3).y) ) return false;
00083 return true;
00084 }
00085
00086 DRect DPath::boundingRect() const
00087 {
00088 if ( size()==0 ) return DRect();
00089 DRect r(at(0).x, at(0).x, at(0).y, at(0).y);
00090 for (uint i=1; i<size(); i++) {
00091 r.setTop( kMin(r.top(), at(i).y) );
00092 r.setBottom( kMax(r.bottom(), at(i).y) );
00093 r.setLeft( kMin(r.left(), at(i).x) );
00094 r.setRight( kMax(r.right(), at(i).x) );
00095 }
00096 return r;
00097 }
00098
00099
00100
00101 QDict<Font::Data> *Font::_dict = 0;
00102 const char *Font::FAMILY_DATA[Nb_Family] = {
00103 "Times", "Helvetica", "Courier", "Symbol"
00104 };
00105
00106 void Font::init()
00107 {
00108 Q_ASSERT( _dict==0 );
00109 _dict = new QDict<Data>(100, false);
00110 _dict->setAutoDelete(true);
00111 }
00112
00113 void Font::cleanup()
00114 {
00115 delete _dict;
00116 _dict = 0;
00117 }
00118
00119 Font::Font()
00120 : _pointSize(12), _color(Qt::black)
00121 {
00122 init("times-roman");
00123 }
00124
00125 Font::Font(const GfxState *state, double size)
00126 {
00127 if ( size<1 ) kdDebug(30516) << "very small font size=" << size << endl;
00128 _pointSize = qRound(size);
00129
00130 GfxRGB rgb;
00131 state->getFillRGB(&rgb);
00132 _color = toColor(rgb);
00133
00134 GfxFont *font = state->getFont();
00135 GString *gname = (font ? font->getName() : 0);
00136 QString name = (gname ? gname->getCString() : 0);
00137
00138 name = name.section('+', 1, 1).lower();
00139 if ( name.isEmpty() ) name = "##dummy";
00140 init(name);
00141 }
00142
00143 struct KnownData {
00144 const char *name;
00145 FontFamily family;
00146 FontStyle style;
00147 bool latex;
00148 };
00149 static const KnownData KNOWN_DATA[] = {
00150
00151 { "times-roman", Times, Regular, false },
00152 { "times-bolditalic", Times, BoldItalic, false },
00153 { "times-bold", Times, Bold, false },
00154 { "times-italic", Times, Italic, false },
00155 { "helvetica-bolditalic", Helvetica, BoldItalic, false },
00156 { "helvetica-bold", Helvetica, Bold, false },
00157 { "helvetica-italic", Times, Italic, false },
00158 { "helvetica", Helvetica, Regular, false },
00159 { "courier-bolditalic", Courier, BoldItalic, false },
00160 { "courier-bold", Courier, Bold, false },
00161 { "courier-italic", Courier, Italic, false },
00162 { "courier", Courier, Regular, false },
00163 { "symbol", Symbol, Regular, false },
00164
00165
00166 { "cmr", Times, Regular, true },
00167 { "cmbx", Times, Bold, true },
00168 { "cmcsc", Times, Regular, true },
00169 { "cmmi", Times, Italic, true },
00170 { "cmtt", Courier, Regular, true },
00171 { "cmsy", Symbol, Regular, true },
00172 { "msbm", Times, Regular, true },
00173
00174 { 0, Nb_Family, Regular, false }
00175 };
00176
00177 void Font::init(const QString &n)
00178 {
00179
00180 _data = _dict->find(n);
00181 if ( _data==0 ) {
00182
00183 QString name = n;
00184 name.replace("oblique", "italic");
00185
00186
00187 _data = new Data;
00188 uint i = 0;
00189 while ( KNOWN_DATA[i].name!=0 ) {
00190 if ( name.find(KNOWN_DATA[i].name)!=-1 ) {
00191
00192
00193 _data->family = FAMILY_DATA[KNOWN_DATA[i].family];
00194 _data->style = KNOWN_DATA[i].style;
00195 _data->latex = KNOWN_DATA[i].latex;
00196 break;
00197 }
00198 i++;
00199 }
00200
00201 if ( _data->family.isEmpty() ) {
00202
00203 kdDebug(30516) << "unknown font : " << n << endl;
00204 if ( name.find("times")!=-1 )
00205 _data->family = FAMILY_DATA[Times];
00206 else if ( name.find("helvetica")!=-1 )
00207 _data->family = FAMILY_DATA[Helvetica];
00208 else if ( name.find("courier")!=-1 )
00209 _data->family = FAMILY_DATA[Courier];
00210 else if ( name.find("symbol")!=-1 )
00211 _data->family = FAMILY_DATA[Symbol];
00212 else {
00213 QFontDatabase fdb;
00214 QStringList list = fdb.families();
00215 list = list.grep(name, false);
00216 if ( !list.isEmpty() ) {
00217 _data->family = list[0];
00218 kdDebug(30516) << "in Qt database as " << list[0] << endl;
00219 }
00220 else {
00221 kdDebug(30516) << "really unknown font !" << endl;
00222 _data->family = name;
00223 }
00224 }
00225
00226 bool italic = ( name.find("italic")!=-1 );
00227 bool bold = ( name.find("bold")!=-1 );
00228 _data->style = toStyle(bold, italic);
00229 _data->latex = false;
00230 }
00231
00232 _dict->insert(name, _data);
00233 }
00234
00235
00236 if ( !_data->height.contains(_pointSize) ) {
00237 QFont font(_data->family, _pointSize,
00238 (isBold(_data->style) ? QFont::Bold : QFont::Normal),
00239 isItalic(_data->style));
00240 QFontMetrics fm(font);
00241 _data->height.insert(_pointSize, fm.height());
00242 }
00243 }
00244
00245 bool Font::operator ==(const Font &font) const
00246 {
00247 if ( _pointSize!=font._pointSize ) return false;
00248 if ( _data->family!=font._data->family ) return false;
00249 if ( _data->style!=font._data->style ) return false;
00250
00251
00252 if ( _color!=font._color ) return false;
00253 return true;
00254 }
00255
00256 bool Font::format(QDomDocument &doc, QDomElement &f,
00257 uint pos, uint len, bool all) const
00258 {
00259 f.setAttribute("id", 1);
00260 if (!all) f.setAttribute("pos", pos);
00261 if (!all) f.setAttribute("len", len);
00262
00263 QDomElement element;
00264 Font def;
00265
00266 if ( all || _data->family!=def._data->family ) {
00267 element = doc.createElement("FONT");
00268 element.setAttribute("name", _data->family);
00269 f.appendChild(element);
00270 }
00271 if ( all || _pointSize!=def._pointSize ) {
00272 element = doc.createElement("SIZE");
00273 element.setAttribute("value", _pointSize);
00274 f.appendChild(element);
00275 }
00276 if ( all || isItalic(_data->style)!=isItalic(def._data->style) ) {
00277 element = doc.createElement("ITALIC");
00278 element.setAttribute("value", (isItalic(_data->style) ? 1 : 0));
00279 f.appendChild(element);
00280 }
00281 if ( all || isBold(_data->style)!=isBold(def._data->style) ) {
00282 element = doc.createElement("WEIGHT");
00283 element.setAttribute("value",
00284 (isBold(_data->style) ? QFont::Bold : QFont::Normal));
00285 f.appendChild(element);
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 if (all) {
00299 element = doc.createElement("VERTALIGN");
00300 element.setAttribute("value", 0);
00301 f.appendChild(element);
00302 }
00303
00304 if ( all || _color!=def._color ) {
00305 element = doc.createElement("COLOR");
00306 element.setAttribute("red", _color.red());
00307 element.setAttribute("green", _color.green());
00308 element.setAttribute("blue", _color.blue());
00309 f.appendChild(element);
00310 }
00311
00312 if (all) {
00313 element = doc.createElement("TEXTBACKGROUNDCOLOR");
00314 element.setAttribute("red", 255);
00315 element.setAttribute("green",255);
00316 element.setAttribute("blue", 255);
00317 f.appendChild(element);
00318 }
00319
00320 return f.hasChildNodes();
00321 }
00322
00323 void Font::setFamily(FontFamily f)
00324 {
00325 int k = -1;
00326 uint i=0;
00327 while ( KNOWN_DATA[i].name!=0 ) {
00328 if ( KNOWN_DATA[i].family==f ) {
00329 if ( KNOWN_DATA[i].style==_data->style ) {
00330 k = i;
00331 break;
00332 }
00333 if ( k==-1 ) k = i;
00334 }
00335 i++;
00336 }
00337 if ( k==-1 ) k = 0;
00338
00339 init(KNOWN_DATA[k].name);
00340 }
00341
00342
00343 Link::Link(const DRect &rect, LinkAction &action, Catalog &catalog)
00344 : _rect(rect)
00345 {
00346 switch ( action.getKind() ) {
00347 case actionGoTo: {
00348 LinkGoTo &lgoto = static_cast<LinkGoTo &>(action);
00349 LinkDest *dest = (lgoto.getDest() ? lgoto.getDest()->copy()
00350 : catalog.findDest( lgoto.getNamedDest() ));
00351 int page = 1;
00352 if (dest) {
00353 if ( dest->isPageRef() ) {
00354 Ref pageref = dest->getPageRef();
00355 page = catalog.findPage(pageref.num, pageref.gen);
00356 } else page = dest->getPageNum();
00357 delete dest;
00358 }
00359
00360 _href = QString("bkm://") + pageLinkName(page);
00361
00362 break;
00363 }
00364
00365 case actionGoToR: {
00366 LinkGoToR &lgotor = static_cast<LinkGoToR &>(action);
00367 _href = "file://";
00368 if ( lgotor.getFileName() )
00369 _href += lgotor.getFileName()->getCString();
00370 int page = 1;
00371 if ( lgotor.getDest() ) {
00372 LinkDest *dest = lgotor.getDest()->copy();
00373 if ( !dest->isPageRef() ) page = dest->getPageNum();
00374 delete dest;
00375 }
00376
00377 kdDebug(30516) << "link to filename \"" << _href << "\" (page "
00378 << page << ")" <<endl;
00379 break;
00380 }
00381
00382 case actionLaunch: {
00383 LinkLaunch &llaunch = static_cast<LinkLaunch &>(action);
00384 _href = "file://";
00385 if ( llaunch.getFileName() )
00386 _href += llaunch.getFileName()->getCString();
00387
00388 kdDebug(30516) << "link to launch/open \"" << _href << "\"" << endl;
00389 break;
00390 }
00391
00392 case actionURI: {
00393 LinkURI &luri = static_cast<LinkURI &>(action);
00394 if ( luri.getURI() ) _href = luri.getURI()->getCString();
00395
00396 kdDebug(30516) << "link to URI \"" << _href << "\"" << endl;
00397 break;
00398 }
00399
00400 case actionMovie:
00401 case actionNamed:
00402 case actionUnknown:
00403 kdDebug(30516) << "unsupported link=" << action.getKind() << endl;
00404 break;
00405 }
00406 }
00407
00408 void Link::format(QDomDocument &doc, QDomElement &f, uint pos,
00409 const QString &text) const
00410 {
00411 f.setAttribute("id", 4);
00412 f.setAttribute("pos", pos);
00413 f.setAttribute("len", 1);
00414
00415 QDomElement v = doc.createElement("VARIABLE");
00416 QDomElement element = doc.createElement("TYPE");
00417 element.setAttribute("type", 9);
00418 element.setAttribute("key", "STRING");
00419 element.setAttribute("text", text);
00420 v.appendChild(element);
00421 element = doc.createElement("LINK");
00422 element.setAttribute("linkName", text);
00423 element.setAttribute("hrefName", _href);
00424 v.appendChild(element);
00425
00426 f.appendChild(v);
00427 }
00428
00429 QString Link::pageLinkName(uint i)
00430 {
00431 return QString("page") + QString::number(i);
00432 }
00433
00434 }