Doxygen
Loading...
Searching...
No Matches
dotfilepatcher.cpp
Go to the documentation of this file.
1/******************************************************************************
2*
3* Copyright (C) 1997-2019 by Dimitri van Heesch.
4*
5* Permission to use, copy, modify, and distribute this software and its
6* documentation under the terms of the GNU General Public License is hereby
7* granted. No representations are made about the suitability of this software
8* for any purpose. It is provided "as is" without express or implied warranty.
9* See the GNU General Public License for more details.
10*
11* Documents produced by Doxygen are derivative works derived from the
12* input used in their production; they are not affected by this license.
13*
14*/
15
16#include "dotfilepatcher.h"
17#include "dotrunner.h"
18#include "config.h"
19#include "message.h"
20#include "docparser.h"
21#include "docnode.h"
22#include "doxygen.h"
23#include "util.h"
24#include "dot.h"
25#include "dir.h"
26#include "portable.h"
27
28// top part of the interactive SVG header
29static const char svgZoomHeader0[] = R"svg(
30<svg id="main" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" onload="init(evt)">
31)svg";
32
33static const char svgZoomHeader0_noinit[] = R"svg(
34<svg id="main" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
35)svg";
36
37static const char svgZoomHeader1[] = R"svg(
38<style type="text/css"><![CDATA[
39.node, .edge {opacity: 0.7;}
40.node.selected, .edge.selected {opacity: 1;}
41.edge:hover path { stroke: red; }
42.edge:hover polygon { stroke: red; fill: red; }
43]]></style>
44)svg";
45
46// conditional part of the interactive SVG header in case the navigation panel is shown
47static const char svgZoomHeader2[] = R"svg(
48<defs>
49 <circle id="rim" cx="0" cy="0" r="7"/>
50 <circle id="rim2" cx="0" cy="0" r="3.5"/>
51 <g id="zoomPlus">
52 <use xlink:href="#rim" fill="#404040"><set attributeName="fill" to="#808080" begin="zoomplus.mouseover" end="zoomplus.mouseout"/></use>
53 <path d="M-4,0h8M0,-4v8" fill="none" stroke="white" stroke-width="1.5" pointer-events="none"/>
54 </g>
55 <g id="zoomMin">
56 <use xlink:href="#rim" fill="#404040"><set attributeName="fill" to="#808080" begin="zoomminus.mouseover" end="zoomminus.mouseout"/></use>
57 <path d="M-4,0h8" fill="none" stroke="white" stroke-width="1.5" pointer-events="none"/>
58 </g>
59 <g id="arrowUp" transform="translate(30 24)">
60 <use xlink:href="#rim"/>
61 <path pointer-events="none" fill="none" stroke="white" stroke-width="1.5" d="M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5"/>
62 </g>
63 <g id="arrowRight" transform="rotate(90) translate(36 -43)">
64 <use xlink:href="#rim"/>
65 <path pointer-events="none" fill="none" stroke="white" stroke-width="1.5" d="M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5"/>
66 </g>
67 <g id="arrowDown" transform="rotate(180) translate(-30 -48)">
68 <use xlink:href="#rim"/>
69 <path pointer-events="none" fill="none" stroke="white" stroke-width="1.5" d="M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5"/>
70 </g>
71 <g id="arrowLeft" transform="rotate(270) translate(-36 17)">
72 <use xlink:href="#rim"/>
73 <path pointer-events="none" fill="none" stroke="white" stroke-width="1.5" d="M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5"/>
74 </g>
75 <g id="resetDef">
76 <use xlink:href="#rim2" fill="#404040"><set attributeName="fill" to="#808080" begin="reset.mouseover" end="reset.mouseout"/></use>
77 </g>
78</defs>
79)svg";
80
81// part of the footer that is needed if the navigation panel is shown
82static const char svgZoomFooter1[] = R"svg(
83<g id="navigator" transform="translate(0 0)" fill="#404254">
84 <rect fill="#f2f5e9" fill-opacity="0.5" stroke="#606060" stroke-width=".5" x="0" y="0" width="60" height="60"/>
85 <use id="zoomplus" xlink:href="#zoomPlus" x="17" y="9" onmousedown="handleZoom(evt,'in')"/>
86 <use id="zoomminus" xlink:href="#zoomMin" x="42" y="9" onmousedown="handleZoom(evt,'out')"/>
87 <use id="reset" xlink:href="#resetDef" x="30" y="36" onmousedown="handleReset()"/>
88 <use id="arrowup" xlink:href="#arrowUp" x="0" y="0" onmousedown="handlePan(0,-1)"/>
89 <use id="arrowright" xlink:href="#arrowRight" x="0" y="0" onmousedown="handlePan(1,0)"/>
90 <use id="arrowdown" xlink:href="#arrowDown" x="0" y="0" onmousedown="handlePan(0,1)"/>
91 <use id="arrowleft" xlink:href="#arrowLeft" x="0" y="0" onmousedown="handlePan(-1,0)"/>
92</g>
93<svg viewBox="0 0 15 15" width="100%" height="30px" preserveAspectRatio="xMaxYMin meet">
94 <g id="arrow_out" transform="scale(0.3 0.3)">
95 <a xlink:href="$orgname" target="_base">
96 <rect id="button" ry="5" rx="5" y="6" x="6" height="38" width="38"
97 fill="#f2f5e9" fill-opacity="0.5" stroke="#606060" stroke-width="1.0"/>
98 <path id="arrow"
99 d="M 11.500037,31.436501 C 11.940474,20.09759 22.043105,11.32322 32.158766,21.979434 L 37.068811,17.246167 C 37.068811,17.246167 37.088388,32 37.088388,32 L 22.160133,31.978069 C 22.160133,31.978069 26.997745,27.140456 26.997745,27.140456 C 18.528582,18.264221 13.291696,25.230495 11.500037,31.436501 z"
100 style="fill:#404040;"/>
101 </a>
102 </g>
103</svg>
104)svg";
105
106// generic part of the interactive SVG footer
107static const char svgZoomFooter2[] = R"svg(
108<style type='text/css'>
109<![CDATA[
110[data-mouse-over-selected='false'] { opacity: 0.7; }
111[data-mouse-over-selected='true'] { opacity: 1.0; }
112]]>
113</style>
114<script type="application/ecmascript"><![CDATA[
115document.addEventListener('DOMContentLoaded', (event) => {
116 highlightEdges();
117 highlightAdjacentNodes();
118});
119]]></script>
120</svg>
121)svg";
122
123static QCString replaceRef(const QCString &buf,const QCString &relPath,
124 bool urlOnly,const QCString &context,const QCString &target=QCString())
125{
126 // search for href="...", store ... part in link
127 QCString href = "href";
128 //bool isXLink=FALSE;
129 int len = 6;
130 int indexS = buf.find("href=\""), indexE = 0;
131 bool targetAlreadySet = buf.find("target=")!=-1;
132 if (indexS>5 && buf.find("xlink:href=\"")!=-1) // XLink href (for SVG)
133 {
134 indexS-=6;
135 len+=6;
136 href.prepend("xlink:");
137 //isXLink=TRUE;
138 }
139 if (indexS>=0 && (indexE=buf.find('"',indexS+len))!=-1)
140 {
141 QCString link = buf.mid(indexS+len,indexE-indexS-len);
142 QCString result;
143 if (urlOnly) // for user defined dot graphs
144 {
145 if (link.startsWith("\\ref ") || link.startsWith("@ref ")) // \ref url
146 {
147 result=href+"=\"";
148 // fake ref node to resolve the url
149 auto parser { createDocParser() };
150 auto dfAst { createRef( *parser.get(), link.mid(5), context ) };
151 auto dfAstImpl = dynamic_cast<const DocNodeAST*>(dfAst.get());
152 const DocRef *df = std::get_if<DocRef>(&dfAstImpl->root);
153 result+=externalRef(relPath,df->ref(),TRUE);
154 if (!df->file().isEmpty())
155 {
156 QCString fn = df->file();
158 result += fn;
159 }
160 if (!df->anchor().isEmpty())
161 {
162 result += "#" + df->anchor();
163 }
164 result += "\"";
165 }
166 else
167 {
168 result = href+"=\"" + link + "\"";
169 }
170 }
171 else // ref$url (external ref via tag file), or $url (local ref)
172 {
173 int marker = link.find('$');
174 if (marker!=-1)
175 {
176 QCString ref = link.left(marker);
177 QCString url = link.mid(marker+1);
178 if (!ref.isEmpty())
179 {
180 result = externalLinkTarget(true);
181 if (!result.isEmpty())targetAlreadySet=true;
182 }
183 result+= href+"=\"";
184 result+=externalRef(relPath,ref,TRUE);
185 result+= url + "\"";
186 }
187 else // should not happen, but handle properly anyway
188 {
189 result = href+"=\"" + link + "\"";
190 }
191 }
192 if (!target.isEmpty() && !targetAlreadySet)
193 {
194 result+=" target=\""+target+"\"";
195 }
196 QCString leftPart = buf.left(indexS);
197 QCString rightPart = buf.mid(indexE+1);
198 //printf("replaceRef(\n'%s'\n)->\n'%s+%s+%s'\n",
199 // qPrint(buf),qPrint(leftPart),qPrint(result),qPrint(rightPart));
200 return leftPart + result + rightPart;
201 }
202 else
203 {
204 return buf;
205 }
206}
207
208/*! converts the rectangles in a client site image map into a stream
209* \param t the stream to which the result is written.
210* \param mapName the name of the map file.
211* \param relPath the relative path to the root of the output directory
212* (used in case CREATE_SUBDIRS is enabled).
213* \param urlOnly if FALSE the url field in the map contains an external
214* references followed by a $ and then the URL.
215* \param context the context (file, class, or namespace) in which the
216* map file was found
217* \returns TRUE if successful.
218*/
220 const QCString &relPath, bool urlOnly,
221 const QCString &context)
222{
223 std::ifstream f = Portable::openInputStream(mapName);
224 if (!f.is_open())
225 {
226 err("problems opening map file {} for inclusion in the docs!\n"
227 "If you installed Graphviz/dot after a previous failing run, \n"
228 "try deleting the output directory and rerun doxygen.\n",mapName);
229 return FALSE;
230 }
231 std::string line;
232 while (getline(f,line)) // foreach line
233 {
234 QCString buf = line+'\n';
235 if (buf.startsWith("<area"))
236 {
237 QCString replBuf = replaceRef(buf,relPath,urlOnly,context);
238 // in dot version 7.0.2 the alt attribute is, incorrectly, removed.
239 // see https://gitlab.com/graphviz/graphviz/-/issues/265
240 int indexA = replBuf.find("alt=");
241 if (indexA == -1)
242 {
243 replBuf = replBuf.left(5) + " alt=\"\"" + replBuf.right(replBuf.length() - 5);
244 }
245
246 // strip id="..." from replBuf since the id's are not needed and not unique.
247 int indexS = replBuf.find("id=\""), indexE = 0;
248 if (indexS>0 && (indexE=replBuf.find('"',indexS+4))!=-1)
249 {
250 t << replBuf.left(indexS-1) << replBuf.right(replBuf.length() - indexE - 1);
251 }
252 else
253 {
254 t << replBuf;
255 }
256 }
257 }
258 return TRUE;
259}
260
262 : m_patchFile(patchFile)
263{
264}
265
267{
268 return m_patchFile.endsWith(".svg");
269}
270
271int DotFilePatcher::addMap(const QCString &mapFile,const QCString &relPath,
272 bool urlOnly,const QCString &context,const QCString &label)
273{
274 size_t id = m_maps.size();
275 m_maps.emplace_back(mapFile,relPath,urlOnly,context,label);
276 return static_cast<int>(id);
277}
278
280 const QCString &figureName,bool heightCheck)
281{
282 size_t id = m_maps.size();
283 m_maps.emplace_back(figureName,"",heightCheck,"",baseName);
284 return static_cast<int>(id);
285}
286
287int DotFilePatcher::addSVGConversion(const QCString &relPath,bool urlOnly,
288 const QCString &context,bool zoomable,
289 int graphId)
290{
291 size_t id = m_maps.size();
292 m_maps.emplace_back("",relPath,urlOnly,context,"",zoomable,graphId);
293 return static_cast<int>(id);
294}
295
297 const QCString &absImgName,
298 const QCString &relPath)
299{
300 size_t id = m_maps.size();
301 m_maps.emplace_back(absImgName,relPath,false,"",baseName);
302 return static_cast<int>(id);
303}
304
306{
307 //printf("DotFilePatcher::run(): %s\n",qPrint(m_patchFile));
308 bool interactiveSVG = Config_getBool(INTERACTIVE_SVG);
309 bool isSVGFile = m_patchFile.endsWith(".svg");
310 int graphId = -1;
311 QCString relPath;
312 if (isSVGFile)
313 {
314 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
315 interactiveSVG = interactiveSVG && map.zoomable;
316 graphId = map.graphId;
317 relPath = map.relPath;
318 //printf("DotFilePatcher::addSVGConversion: file=%s zoomable=%d\n",
319 // qPrint(m_patchFile),map->zoomable);
320 }
321 QCString tmpName = m_patchFile+".tmp";
322 Dir thisDir;
323 if (!thisDir.rename(m_patchFile.str(),tmpName.str()))
324 {
325 err("Failed to rename file {} to {}!\n",m_patchFile,tmpName);
326 return FALSE;
327 }
328 std::ifstream fi = Portable::openInputStream(tmpName);
329 std::ofstream fo = Portable::openOutputStream(m_patchFile);
330 if (!fi.is_open())
331 {
332 err("problem opening file {} for patching!\n",tmpName);
333 thisDir.rename(tmpName.str(),m_patchFile.str());
334 return FALSE;
335 }
336 if (!fo.is_open())
337 {
338 err("problem opening file {} for patching!\n",m_patchFile);
339 thisDir.rename(tmpName.str(),m_patchFile.str());
340 return FALSE;
341 }
342 TextStream t(&fo);
343 int width=0,height=0;
344 bool insideHeader=FALSE;
345 bool replacedHeader=FALSE;
346 bool useNagivation=FALSE;
347 std::string lineStr;
348 static const reg::Ex reSVG(R"([\[<]!-- SVG [0-9]+)");
349 static const reg::Ex reMAP(R"(<!-- MAP [0-9]+)");
350 static const reg::Ex reFIG(R"(% FIG [0-9]+)");
351
352 while (getline(fi,lineStr))
353 {
354 QCString line = lineStr+'\n';
355 //printf("line=[%s]\n",qPrint(line.stripWhiteSpace()));
356 int i = 0;
357 if (isSVGFile)
358 {
359 if (interactiveSVG)
360 {
361 if (line.find("<svg")!=-1 && !replacedHeader)
362 {
363 int count = sscanf(line.data(),"<svg width=\"%dpt\" height=\"%dpt\"",&width,&height);
364 if (count != 2) count = sscanf(line.data(),"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"%d\"",&width,&height);
365 //printf("width=%d height=%d\n",width,height);
366 useNagivation = count==2 && (width>500 || height>450);
367 insideHeader = count==2;
368 }
369 else if (insideHeader && !replacedHeader && line.find("<g id=\"graph")!=-1)
370 {
371 if (useNagivation)
372 {
373 // insert special replacement header for interactive SVGs
374 t << "<!--zoomable " << height << " -->\n";
375 t << svgZoomHeader0;
376 }
377 else
378 {
380 }
381 t << svgZoomHeader1;
382 if (useNagivation)
383 {
384 t << svgZoomHeader2;
385 }
386 if (useNagivation)
387 {
388 t << "<script type=\"application/ecmascript\">\n";
389 t << "var viewWidth = " << width << ";\n";
390 t << "var viewHeight = " << height << ";\n";
391 if (graphId>=0)
392 {
393 t << "var sectionId = 'dynsection-" << graphId << "';\n";
394 }
395 t << "</script>\n";
396 }
397 t << "<script type=\"application/ecmascript\" xlink:href=\"" << relPath << "svg.min.js\"/>\n";
398 t << "<svg id=\"graph\" class=\"graph\">\n";
399
400 if (useNagivation)
401 {
402 t << "<g id=\"viewport\">\n";
403 }
404 else
405 {
406 t << line;
407 }
408 line="";
409 insideHeader=FALSE;
410 replacedHeader=TRUE;
411 }
412 }
413 if (!insideHeader || !useNagivation) // copy SVG and replace refs,
414 // unless we are inside the header of the SVG.
415 // Then we replace it with another header.
416 {
417 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
418 t << replaceRef(line,map.relPath,map.urlOnly,map.context,"_top");
419 }
420 }
421 else if (line.find("SVG")!=-1 && (i=findIndex(line.str(),reSVG))!=-1)
422 {
423 //printf("Found marker at %d\n",i);
424 int mapId=-1;
425 t << line.left(i);
426 int n = sscanf(line.data()+i+1,"!-- SVG %d",&mapId);
427 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
428 {
429 int e = std::max(line.find("--]"),line.find("-->"));
430 const Map &map = m_maps.at(mapId);
431 //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n",
432 // qPrint(m_patchFile),map.zoomable);
433 if (!writeSVGFigureLink(t,map.relPath,map.label,map.mapFile))
434 {
435 err("Problem extracting size from SVG file {}\n",map.mapFile);
436 }
437 if (e!=-1) t << line.mid(e+3);
438 }
439 else // error invalid map id!
440 {
441 err("Found invalid SVG id in file {}!\n",m_patchFile);
442 t << line.mid(i);
443 }
444 }
445 else if (line.find("MAP")!=-1 && (i=findIndex(line.str(),reMAP))!=-1)
446 {
447 int mapId=-1;
448 t << line.left(i);
449 int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId);
450 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
451 {
452 TextStream tt;
453 const Map &map = m_maps.at(mapId);
454 //printf("patching MAP %d in file %s with contents of %s\n",
455 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
456 convertMapFile(tt,map.mapFile,map.relPath,map.urlOnly,map.context);
457 if (!tt.empty())
458 {
459 t << "<map name=\"" << correctId(map.label) << "\" id=\"" << correctId(map.label) << "\">\n";
460 t << tt.str();
461 t << "</map>\n";
462 }
463 }
464 else // error invalid map id!
465 {
466 err("Found invalid MAP id in file {}!\n",m_patchFile);
467 t << line.mid(i);
468 }
469 }
470 else if (line.find("FIG")!=-1 && (i=findIndex(line.str(),reFIG))!=-1)
471 {
472 int mapId=-1;
473 int n = sscanf(line.data()+i+2,"FIG %d",&mapId);
474 //printf("line='%s' n=%d\n",qPrint(line)+i,n);
475 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
476 {
477 const Map &map = m_maps.at(mapId);
478 //printf("patching FIG %d in file %s with contents of %s\n",
479 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
480 if (!writeVecGfxFigure(t,map.label,map.mapFile))
481 {
482 err("problem writing FIG {} figure!\n",mapId);
483 return FALSE;
484 }
485 }
486 else // error invalid map id!
487 {
488 err("Found invalid bounding FIG {} in file {}!\n",mapId,m_patchFile);
489 t << line;
490 }
491 }
492 else
493 {
494 t << line;
495 }
496 }
497 if (isSVGFile && interactiveSVG && !useNagivation) t << "</svg>\n";
498
499 fi.close();
500 if (isSVGFile && interactiveSVG && replacedHeader)
501 {
502 QCString orgName=m_patchFile.left(m_patchFile.length()-4)+"_org.svg";
503 if (useNagivation)
504 {
505 t << substitute(svgZoomFooter1,"$orgname",stripPath(orgName));
506 }
507 t << svgZoomFooter2;
508 t.flush();
509 fo.close();
510 // keep original SVG file so we can refer to it, we do need to replace
511 // dummy link by real ones
512 fi = Portable::openInputStream(tmpName);
513 fo = Portable::openOutputStream(orgName);
514 if (!fi.is_open())
515 {
516 err("problem opening file {} for reading!\n",tmpName);
517 return FALSE;
518 }
519 if (!fo.is_open())
520 {
521 err("problem opening file {} for writing!\n",orgName);
522 return FALSE;
523 }
524 t.setStream(&fo);
525 while (getline(fi,lineStr)) // foreach line
526 {
527 std::string line = lineStr+'\n';
528 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
529 t << replaceRef(line.c_str(),map.relPath,map.urlOnly,map.context,"_top");
530 }
531 t.flush();
532 fi.close();
533 fo.close();
534 }
535 // remove temporary file
536 thisDir.remove(tmpName.str());
537 return TRUE;
538}
539
540//---------------------------------------------------------------------------------------------
541
542
543// extract size from a dot generated SVG file
544static bool readSVGSize(const QCString &fileName,int *width,int *height)
545{
546 bool found=FALSE;
547 std::ifstream f = Portable::openInputStream(fileName);
548 if (!f.is_open())
549 {
550 return false;
551 }
552 std::string line;
553 while (getline(f,line) && !found)
554 {
555 if (qstrncmp(line.c_str(),"<!--zoomable ",13)==0)
556 {
557 *width=-1;
558 *height=-1;
559 sscanf(line.c_str(),"<!--zoomable %d",height);
560 found=true;
561 }
562 else if (sscanf(line.c_str(),"<svg width=\"%dpt\" height=\"%dpt\"",width,height)==2)
563 {
564 found=true;
565 }
566 else if (sscanf(line.c_str(),"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"%d\"",width,height)==2)
567 {
568 found=true;
569 }
570 }
571 return true;
572}
573
575{
576 out << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
577}
578
579/// Check if a reference to a SVG figure can be written and do so if possible.
580/// Returns FALSE if not possible (for instance because the SVG file is not yet generated).
582 const QCString &baseName,const QCString &absImgName)
583{
584 int width=600,height=600;
585 if (!readSVGSize(absImgName,&width,&height))
586 {
587 return FALSE;
588 }
589 if (width==-1)
590 {
591 if (height<=60) height=300; else height+=300; // add some extra space for zooming
592 if (height>600) height=600; // clip to maximum height of 600 pixels
593 out << "<div class=\"zoom\">";
594 //out << "<object type=\"image/svg+xml\" data=\""
595 //out << "<embed type=\"image/svg+xml\" src=\""
596 out << "<iframe scrolling=\"no\" frameborder=\"0\" src=\""
597 << relPath << baseName << ".svg\" width=\"100%\" height=\"" << height << "\">";
598 }
599 else
600 {
601 //out << "<object type=\"image/svg+xml\" data=\""
602 //out << "<embed type=\"image/svg+xml\" src=\""
603 out << "<iframe scrolling=\"no\" frameborder=\"0\" src=\""
604 << relPath << baseName << ".svg\" width=\""
605 << ((width*96+48)/72) << "\" height=\""
606 << ((height*96+48)/72) << "\">";
607 }
609 //out << "</object>";
610 //out << "</embed>";
611 out << "</iframe>";
612 if (width==-1)
613 {
614 out << "</div>";
615 }
616
617 return TRUE;
618}
619
621 const QCString &figureName)
622{
623 int width=400,height=550;
624 if (Config_getBool(USE_PDFLATEX))
625 {
626 if (!DotRunner::readBoundingBox(figureName+".pdf",&width,&height,FALSE))
627 {
628 //printf("writeVecGfxFigure()=0\n");
629 return FALSE;
630 }
631 }
632 else
633 {
634 if (!DotRunner::readBoundingBox(figureName+".eps",&width,&height,TRUE))
635 {
636 //printf("writeVecGfxFigure()=0\n");
637 return FALSE;
638 }
639 }
640 //printf("Got PDF/EPS size %d,%d\n",width,height);
641 int maxWidth = 350; /* approx. page width in points, excl. margins */
642 int maxHeight = 550; /* approx. page height in points, excl. margins */
643 out << "\\nopagebreak\n"
644 "\\begin{figure}[H]\n"
645 "\\begin{center}\n"
646 "\\leavevmode\n";
647 if (width>maxWidth || height>maxHeight) // figure too big for page
648 {
649 // c*width/maxWidth > c*height/maxHeight, where c=maxWidth*maxHeight>0
650 if (width*maxHeight>height*maxWidth)
651 {
652 out << "\\includegraphics[width=" << maxWidth << "pt]";
653 }
654 else
655 {
656 out << "\\includegraphics[height=" << maxHeight << "pt]";
657 }
658 }
659 else
660 {
661 out << "\\includegraphics[width=" << width << "pt]";
662 }
663
664 out << "{" << baseName << "}\n"
665 "\\end{center}\n"
666 "\\end{figure}\n";
667
668 //printf("writeVecGfxFigure()=1\n");
669 return TRUE;
670}
Class representing a directory in the file system.
Definition dir.h:75
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
bool rename(const std::string &orgName, const std::string &newName, bool acceptsAbsPath=true) const
Definition dir.cpp:321
Class representing the abstract syntax tree of a documentation block.
Definition docnode.h:1460
Node representing a reference to some item.
Definition docnode.h:772
QCString anchor() const
Definition docnode.h:779
QCString file() const
Definition docnode.h:776
QCString ref() const
Definition docnode.h:778
static bool writeVecGfxFigure(TextStream &out, const QCString &baseName, const QCString &figureName)
static bool convertMapFile(TextStream &t, const QCString &mapName, const QCString &relPath, bool urlOnly=FALSE, const QCString &context=QCString())
bool isSVGFile() const
DotFilePatcher(const QCString &patchFile)
std::vector< Map > m_maps
int addSVGObject(const QCString &baseName, const QCString &figureName, const QCString &relPath)
int addMap(const QCString &mapFile, const QCString &relPath, bool urlOnly, const QCString &context, const QCString &label)
int addSVGConversion(const QCString &relPath, bool urlOnly, const QCString &context, bool zoomable, int graphId)
QCString m_patchFile
static bool writeSVGFigureLink(TextStream &out, const QCString &relPath, const QCString &baseName, const QCString &absImgName)
Check if a reference to a SVG figure can be written and do so if possible.
int addFigure(const QCString &baseName, const QCString &figureName, bool heightCheck)
static bool readBoundingBox(const QCString &fileName, int *width, int *height, bool isEps)
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
QCString & prepend(const char *s)
Definition qcstring.h:407
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
bool startsWith(const char *s) const
Definition qcstring.h:492
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:537
QCString right(size_t len) const
Definition qcstring.h:219
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
QCString left(size_t len) const
Definition qcstring.h:214
Text streaming class that buffers data.
Definition textstream.h:36
bool empty() const
Returns true iff the buffer is empty.
Definition textstream.h:253
void setStream(std::ostream *s)
Sets or changes the std::ostream to write to.
Definition textstream.h:67
void flush()
Flushes the buffer.
Definition textstream.h:209
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:229
Class representing a regular expression.
Definition regex.h:39
#define Config_getBool(name)
Definition config.h:33
IDocParserPtr createDocParser()
factory function to create a parser
Definition docparser.cpp:54
IDocNodeASTPtr createRef(IDocParser &parserIntf, const QCString &target, const QCString &context, const QCString &srcFile, int srcLine)
static bool readSVGSize(const QCString &fileName, int *width, int *height)
static void writeSVGNotSupported(TextStream &out)
static const char svgZoomHeader1[]
static const char svgZoomHeader2[]
static QCString replaceRef(const QCString &buf, const QCString &relPath, bool urlOnly, const QCString &context, const QCString &target=QCString())
static const char svgZoomHeader0_noinit[]
static const char svgZoomFooter2[]
static const char svgZoomHeader0[]
static const char svgZoomFooter1[]
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:665
Portable versions of functions that are platform dependent.
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:477
int qstrncmp(const char *str1, const char *str2, size_t len)
Definition qcstring.h:75
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
QCString externalRef(const QCString &relPath, const QCString &ref, bool href)
Definition util.cpp:6162
QCString stripPath(const QCString &s)
Definition util.cpp:5388
bool found
Definition util.cpp:984
int findIndex(const StringVector &sv, const std::string &s)
find the index of a string in a vector of strings, returns -1 if the string could not be found
Definition util.cpp:7078
QCString correctId(const QCString &s)
Definition util.cpp:4345
QCString externalLinkTarget(const bool parent)
Definition util.cpp:6118
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:5339
A bunch of utility functions.