filters

misc.cpp
1/*
2 * Copyright (c) 2002-2003 Nicolas HADACEK (hadacek@kde.org)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "misc.h"
21
22#include <math.h>
23#include <tqfontmetrics.h>
24#include <tqfontdatabase.h>
25#include <tdeglobal.h>
26#include <kdebug.h>
27
28#include "Link.h"
29#include "Catalog.h"
30#include "GfxState.h"
31#include "GfxFont.h"
32
33
34namespace PDFImport
35{
36
37
38TQColor toColor(GfxRGB &rgb)
39{
40 return TQColor(tqRound(rgb.r*255), tqRound(rgb.g*255), tqRound(rgb.b*255));
41}
42
43//-----------------------------------------------------------------------------
44bool DRect::operator ==(const DRect &r) const
45{
46 return ( equal(_top, r._top) && equal(_bottom, r._bottom)
47 && equal(_left, r._left) && equal(_right, r._right) );
48}
49
50bool DRect::isInside(const DRect &r, double percent) const
51{
52 return ( more(r._top, _top, percent) && less(r._bottom, _bottom, percent)
53 && more(r._left, _left, percent)
54 && less(r._right, _right, percent) );
55}
56
57void DRect::unite(const DRect &r)
58{
59 if ( !r.isValid() ) return;
60 if ( !isValid() ) {
61 *this = r;
62 return;
63 }
64 _left = kMin(_left, r._left);
65 _right = kMax(_right, r._right);
66 _top = kMin(_top, r._top);
67 _bottom = kMax(_bottom, r._bottom);
68}
69
70TQString DRect::toString() const
71{
72 if ( !isValid() ) return "invalid rect";
73 return TQString("left=%1 right=%2 top=%3 bottom=%4").arg(_left).arg(_right)
74 .arg(_top).arg(_bottom);
75}
76
77bool DPath::isRectangle() const
78{
79 if ( size()!=5 ) return false;
80 if ( !equal(at(0).x, at(3).x) || !equal(at(0).x, at(4).x) ) return false;
81 if ( !equal(at(0).y, at(1).y) || !equal(at(0).y, at(4).y) ) return false;
82 if ( !equal(at(1).x, at(2).x) || !equal(at(2).y, at(3).y) ) return false;
83 return true;
84}
85
86DRect DPath::boundingRect() const
87{
88 if ( size()==0 ) return DRect();
89 DRect r(at(0).x, at(0).x, at(0).y, at(0).y);
90 for (uint i=1; i<size(); i++) {
91 r.setTop( kMin(r.top(), at(i).y) );
92 r.setBottom( kMax(r.bottom(), at(i).y) );
93 r.setLeft( kMin(r.left(), at(i).x) );
94 r.setRight( kMax(r.right(), at(i).x) );
95 }
96 return r;
97}
98
99
100//-----------------------------------------------------------------------------
101TQDict<Font::Data> *Font::_dict = 0;
102const char *Font::FAMILY_DATA[Nb_Family] = {
103 "Times", "Helvetica", "Courier", "Symbol"
104};
105
106void Font::init()
107{
108 Q_ASSERT( _dict==0 );
109 _dict = new TQDict<Data>(100, false); // case insensitive
110 _dict->setAutoDelete(true);
111}
112
113void Font::cleanup()
114{
115 delete _dict;
116 _dict = 0;
117}
118
119Font::Font()
120 : _pointSize(12), _color(TQt::black)
121{
122 init("times-roman");
123}
124
125Font::Font(const GfxState *state, double size)
126{
127 if ( size<1 ) kdDebug(30516) << "very small font size=" << size << endl;
128 _pointSize = tqRound(size);
129
130 GfxRGB rgb;
131 state->getFillRGB(&rgb);
132 _color = toColor(rgb);
133
134 GfxFont *font = state->getFont();
135 GString *gname = (font ? font->getName() : 0);
136 TQString name = (gname ? gname->getCString() : 0);
137// kdDebug(30516) << "font: " << name << endl;
138 name = name.section('+', 1, 1).lower();
139 if ( name.isEmpty() ) name = "##dummy"; // dummy name
140 init(name);
141}
142
143struct KnownData {
144 const char *name;
145 FontFamily family;
146 FontStyle style;
147 bool latex;
148};
149static const KnownData KNOWN_DATA[] = {
150 // standard XPDF fonts (the order is important for finding !)
151 { "times-roman", Times, Regular, false },
152 { "times-bolditalic", Times, BoldItalic, false },
153 { "times-bold", Times, Bold, false },
154 { "times-italic", Times, Italic, false },
155 { "helvetica-bolditalic", Helvetica, BoldItalic, false },
156 { "helvetica-bold", Helvetica, Bold, false },
157 { "helvetica-italic", Times, Italic, false },
158 { "helvetica", Helvetica, Regular, false },
159 { "courier-bolditalic", Courier, BoldItalic, false },
160 { "courier-bold", Courier, Bold, false },
161 { "courier-italic", Courier, Italic, false },
162 { "courier", Courier, Regular, false },
163 { "symbol", Symbol, Regular, false },
164
165 // some latex fonts
166 { "cmr", Times, Regular, true },
167 { "cmbx", Times, Bold, true },
168 { "cmcsc", Times, Regular, true }, // small caps
169 { "cmmi", Times, Italic, true },
170 { "cmtt", Courier, Regular, true },
171 { "cmsy", Symbol, Regular, true },
172 { "msbm", Times, Regular, true }, // math caps
173
174 { 0, Nb_Family, Regular, false }
175};
176
177void Font::init(const TQString &n)
178{
179 // check if font already parsed
180 _data = _dict->find(n);
181 if ( _data==0 ) {
182// kdDebug(30516) << "font " << n << endl;
183 TQString name = n;
184 name.replace("oblique", "italic");
185
186 // check if known font
187 _data = new Data;
188 uint i = 0;
189 while ( KNOWN_DATA[i].name!=0 ) {
190 if ( name.find(KNOWN_DATA[i].name)!=-1 ) {
191// kdDebug(30516) << "found " << KNOWN_DATA[i].name
192// << " " << isBold(KNOWN_DATA[i].style) << endl;
193 _data->family = FAMILY_DATA[KNOWN_DATA[i].family];
194 _data->style = KNOWN_DATA[i].style;
195 _data->latex = KNOWN_DATA[i].latex;
196 break;
197 }
198 i++;
199 }
200
201 if ( _data->family.isEmpty() ) { // let's try harder
202 // simple heuristic
203 kdDebug(30516) << "unknown font : " << n << endl;
204 if ( name.find("times")!=-1 )
205 _data->family = FAMILY_DATA[Times];
206 else if ( name.find("helvetica")!=-1 )
207 _data->family = FAMILY_DATA[Helvetica];
208 else if ( name.find("courier")!=-1 )
209 _data->family = FAMILY_DATA[Courier];
210 else if ( name.find("symbol")!=-1 )
211 _data->family = FAMILY_DATA[Symbol];
212 else { // with TQt
213 TQFontDatabase fdb;
214 TQStringList list = fdb.families();
215 list = list.grep(name, false);
216 if ( !list.isEmpty() ) {
217 _data->family = list[0];
218 kdDebug(30516) << "in TQt database as " << list[0] << endl;
219 }
220 else {
221 kdDebug(30516) << "really unknown font !" << endl;
222 _data->family = name;
223 }
224 }
225
226 bool italic = ( name.find("italic")!=-1 );
227 bool bold = ( name.find("bold")!=-1 );
228 _data->style = toStyle(bold, italic);
229 _data->latex = false;
230 }
231
232 _dict->insert(name, _data);
233 }
234
235 // check if TQFont already created
236 if ( !_data->height.contains(_pointSize) ) {
237 TQFont font(_data->family, _pointSize,
238 (isBold(_data->style) ? TQFont::Bold : TQFont::Normal),
239 isItalic(_data->style));
240 TQFontMetrics fm(font);
241 _data->height.insert(_pointSize, fm.height());
242 }
243}
244
245bool Font::operator ==(const Font &font) const
246{
247 if ( _pointSize!=font._pointSize ) return false;
248 if ( _data->family!=font._data->family ) return false;
249 if ( _data->style!=font._data->style ) return false;
250// if ( _underline!=font._underline ) return false;
251// if ( _strikeOut!=font._strikeOut ) return false;
252 if ( _color!=font._color ) return false;
253 return true;
254}
255
256bool Font::format(TQDomDocument &doc, TQDomElement &f,
257 uint pos, uint len, bool all) const
258{
259 f.setAttribute("id", 1);
260 if (!all) f.setAttribute("pos", pos);
261 if (!all) f.setAttribute("len", len);
262
263 TQDomElement element;
264 Font def;
265
266 if ( all || _data->family!=def._data->family ) {
267 element = doc.createElement("FONT");
268 element.setAttribute("name", _data->family);
269 f.appendChild(element);
270 }
271 if ( all || _pointSize!=def._pointSize ) {
272 element = doc.createElement("SIZE");
273 element.setAttribute("value", _pointSize);
274 f.appendChild(element);
275 }
276 if ( all || isItalic(_data->style)!=isItalic(def._data->style) ) {
277 element = doc.createElement("ITALIC");
278 element.setAttribute("value", (isItalic(_data->style) ? 1 : 0));
279 f.appendChild(element);
280 }
281 if ( all || isBold(_data->style)!=isBold(def._data->style) ) {
282 element = doc.createElement("WEIGHT");
283 element.setAttribute("value",
284 (isBold(_data->style) ? TQFont::Bold : TQFont::Normal));
285 f.appendChild(element);
286 }
287// if ( all || _underline!=def._underline ) {
288// element = doc.createElement("UNDERLINE");
289// element.setAttribute("value", (_underline ? 1 : 0));
290// f.appendChild(element);
291// }
292// if ( all || _strikeOut!=def._strikeOut ) {
293// element = doc.createElement("STRIKEOUT");
294// element.setAttribute("value", (_strikeOut ? 1 : 0));
295// f.appendChild(element);
296// }
297
298 if (all) {
299 element = doc.createElement("VERTALIGN");
300 element.setAttribute("value", 0);
301 f.appendChild(element);
302 }
303
304 if ( all || _color!=def._color ) {
305 element = doc.createElement("COLOR");
306 element.setAttribute("red", _color.red());
307 element.setAttribute("green", _color.green());
308 element.setAttribute("blue", _color.blue());
309 f.appendChild(element);
310 }
311
312 if (all) { // #### FIXME
313 element = doc.createElement("TEXTBACKGROUNDCOLOR");
314 element.setAttribute("red", 255);
315 element.setAttribute("green",255);
316 element.setAttribute("blue", 255);
317 f.appendChild(element);
318 }
319
320 return f.hasChildNodes();
321}
322
323void Font::setFamily(FontFamily f)
324{
325 int k = -1;
326 uint i=0;
327 while ( KNOWN_DATA[i].name!=0 ) {
328 if ( KNOWN_DATA[i].family==f ) {
329 if ( KNOWN_DATA[i].style==_data->style ) {
330 k = i;
331 break;
332 }
333 if ( k==-1 ) k = i;
334 }
335 i++;
336 }
337 if ( k==-1 ) k = 0;
338
339 init(KNOWN_DATA[k].name);
340}
341
342//-----------------------------------------------------------------------------
343Link::Link(const DRect &rect, LinkAction &action, Catalog &catalog)
344 : _rect(rect)
345{
346 switch ( action.getKind() ) {
347 case actionGoTo: {
348 LinkGoTo &lgoto = static_cast<LinkGoTo &>(action);
349 LinkDest *dest = (lgoto.getDest() ? lgoto.getDest()->copy()
350 : catalog.findDest( lgoto.getNamedDest() ));
351 int page = 1;
352 if (dest) {
353 if ( dest->isPageRef() ) {
354 Ref pageref = dest->getPageRef();
355 page = catalog.findPage(pageref.num, pageref.gen);
356 } else page = dest->getPageNum();
357 delete dest;
358 }
359
360 _href = TQString("bkm://") + pageLinkName(page);
361// kdDebug(30516) << "link to page " << page << endl;
362 break;
363 }
364
365 case actionGoToR: {
366 LinkGoToR &lgotor = static_cast<LinkGoToR &>(action);
367 _href = "file://";
368 if ( lgotor.getFileName() )
369 _href += lgotor.getFileName()->getCString();
370 int page = 1;
371 if ( lgotor.getDest() ) {
372 LinkDest *dest = lgotor.getDest()->copy();
373 if ( !dest->isPageRef() ) page = dest->getPageNum();
374 delete dest;
375 }
376
377 kdDebug(30516) << "link to filename \"" << _href << "\" (page "
378 << page << ")" <<endl;
379 break;
380 }
381
382 case actionLaunch: {
383 LinkLaunch &llaunch = static_cast<LinkLaunch &>(action);
384 _href = "file://";
385 if ( llaunch.getFileName() )
386 _href += llaunch.getFileName()->getCString();
387
388 kdDebug(30516) << "link to launch/open \"" << _href << "\"" << endl;
389 break;
390 }
391
392 case actionURI: {
393 LinkURI &luri = static_cast<LinkURI &>(action);
394 if ( luri.getURI() ) _href = luri.getURI()->getCString();
395
396 kdDebug(30516) << "link to URI \"" << _href << "\"" << endl;
397 break;
398 }
399
400 case actionMovie:
401 case actionNamed:
402 case actionUnknown:
403 kdDebug(30516) << "unsupported link=" << action.getKind() << endl;
404 break;
405 }
406}
407
408void Link::format(TQDomDocument &doc, TQDomElement &f, uint pos,
409 const TQString &text) const
410{
411 f.setAttribute("id", 4);
412 f.setAttribute("pos", pos);
413 f.setAttribute("len", 1);
414
415 TQDomElement v = doc.createElement("VARIABLE");
416 TQDomElement element = doc.createElement("TYPE");
417 element.setAttribute("type", 9);
418 element.setAttribute("key", "STRING");
419 element.setAttribute("text", text);
420 v.appendChild(element);
421 element = doc.createElement("LINK");
422 element.setAttribute("linkName", text);
423 element.setAttribute("hrefName", _href);
424 v.appendChild(element);
425
426 f.appendChild(v);
427}
428
429TQString Link::pageLinkName(uint i)
430{
431 return TQString("page") + TQString::number(i);
432}
433
434} // namespace