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