PageRenderTime 1648ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/ExtLibs/wxWidgets/src/html/m_layout.cpp

https://bitbucket.org/lennonchan/cafu
C++ | 460 lines | 297 code | 100 blank | 63 comment | 37 complexity | e0dad396b50741bc8b40ae34384cfcfd MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/html/m_layout.cpp
  3. // Purpose: wxHtml module for basic paragraphs/layout handling
  4. // Author: Vaclav Slavik
  5. // RCS-ID: $Id$
  6. // Copyright: (c) 1999 Vaclav Slavik
  7. // Licence: wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9. #include "wx/wxprec.h"
  10. #ifdef __BORLANDC__
  11. #pragma hdrstop
  12. #endif
  13. #if wxUSE_HTML && wxUSE_STREAMS
  14. #ifndef WX_PRECOMP
  15. #include "wx/image.h"
  16. #endif
  17. #include "wx/html/forcelnk.h"
  18. #include "wx/html/m_templ.h"
  19. #include "wx/html/htmlwin.h"
  20. FORCE_LINK_ME(m_layout)
  21. #ifdef __WXWINCE__
  22. #include "wx/msw/wince/missing.h" // for bsearch()
  23. #else
  24. #include <stdlib.h> // bsearch()
  25. #endif
  26. //-----------------------------------------------------------------------------
  27. // wxHtmlPageBreakCell
  28. //-----------------------------------------------------------------------------
  29. // Since html isn't a page-layout language, it doesn't support page
  30. // page breaks directly--that requires CSS2 support. But a page-break
  31. // facility is handy, and has been requested more than once on the
  32. // mailing lists. This wxHtml tag handler implements just enough of
  33. // CSS2 to support a page break by recognizing only
  34. // <div style="page-break-before:always">
  35. //
  36. // wxHtml maintains page breaks in wxHtmlPrintout::m_PageBreaks. The
  37. // tag handler below adds appropriate offsets to that array member.
  38. // wxHtmlDCRenderer::Render() accesses that array and makes a new page
  39. // begin after each page-break tag.
  40. // The page-break handler does all its work in AdjustPagebreak(). For
  41. // all tag handlers, that function adjusts the page-break position.
  42. // For other tags, it determines whether the html element can fit on
  43. // the remainder of the page; if it cannot fit, but must not be split,
  44. // then the function moves the page break provided in the argument up,
  45. // and returns 'true' to inform the caller that the argument was
  46. // modified.
  47. //
  48. // Due to its special purpose, the page-break facility differs from
  49. // other tags. It takes up no space, but it behaves as though there is
  50. // never enough room to fit it on the remainder of the page--it always
  51. // forces a page break. Therefore, unlike other elements that trigger
  52. // a page break, it would never 'fit' on the following page either.
  53. // Therefore it's necessary to compare each pagebreak candidate to the
  54. // array wxHtmlPrintout::m_PageBreaks of pagebreaks already set, and
  55. // set a new one only if it's not in that array.
  56. class wxHtmlPageBreakCell : public wxHtmlCell
  57. {
  58. public:
  59. wxHtmlPageBreakCell() {}
  60. bool AdjustPagebreak(int* pagebreak,
  61. wxArrayInt& known_pagebreaks) const;
  62. void Draw(wxDC& WXUNUSED(dc),
  63. int WXUNUSED(x), int WXUNUSED(y),
  64. int WXUNUSED(view_y1), int WXUNUSED(view_y2),
  65. wxHtmlRenderingInfo& WXUNUSED(info)) {}
  66. private:
  67. wxDECLARE_NO_COPY_CLASS(wxHtmlPageBreakCell);
  68. };
  69. bool wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak, wxArrayInt& known_pagebreaks) const
  70. {
  71. // When we are counting pages, 'known_pagebreaks' is non-NULL.
  72. // That's the only time we change 'pagebreak'. Otherwise, pages
  73. // were already counted, 'known_pagebreaks' is NULL, and we don't
  74. // do anything except return false.
  75. //
  76. // We also simply return false if the 'pagebreak' argument is
  77. // less than (vertically above) or the same as the current
  78. // vertical position. Otherwise we'd be setting a pagebreak above
  79. // the current cell, which is incorrect, or duplicating a
  80. // pagebreak that has already been set.
  81. if( known_pagebreaks.GetCount() == 0 || *pagebreak <= m_PosY)
  82. {
  83. return false;
  84. }
  85. // m_PosY is only the vertical offset from the parent. The pagebreak
  86. // required here is the total page offset, so m_PosY must be added
  87. // to the parent's offset and height.
  88. int total_height = m_PosY;
  89. for ( wxHtmlCell *parent = GetParent(); parent; parent = parent->GetParent() )
  90. {
  91. total_height += parent->GetPosY();
  92. }
  93. // Search the array of pagebreaks to see whether we've already set
  94. // a pagebreak here.
  95. int where = known_pagebreaks.Index( total_height);
  96. // Add a pagebreak only if there isn't one already set here.
  97. if( wxNOT_FOUND != where)
  98. {
  99. return false;
  100. }
  101. else
  102. {
  103. *pagebreak = m_PosY;
  104. return true;
  105. }
  106. }
  107. TAG_HANDLER_BEGIN(P, "P")
  108. TAG_HANDLER_CONSTR(P) { }
  109. TAG_HANDLER_PROC(tag)
  110. {
  111. if (m_WParser->GetContainer()->GetFirstChild() != NULL)
  112. {
  113. m_WParser->CloseContainer();
  114. m_WParser->OpenContainer();
  115. }
  116. m_WParser->GetContainer()->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
  117. m_WParser->GetContainer()->SetAlign(tag);
  118. return false;
  119. }
  120. TAG_HANDLER_END(P)
  121. TAG_HANDLER_BEGIN(BR, "BR")
  122. TAG_HANDLER_CONSTR(BR) { }
  123. TAG_HANDLER_PROC(tag)
  124. {
  125. int al = m_WParser->GetContainer()->GetAlignHor();
  126. wxHtmlContainerCell *c;
  127. m_WParser->CloseContainer();
  128. c = m_WParser->OpenContainer();
  129. c->SetAlignHor(al);
  130. c->SetAlign(tag);
  131. c->SetMinHeight(m_WParser->GetCharHeight());
  132. return false;
  133. }
  134. TAG_HANDLER_END(BR)
  135. TAG_HANDLER_BEGIN(CENTER, "CENTER")
  136. TAG_HANDLER_CONSTR(CENTER) { }
  137. TAG_HANDLER_PROC(tag)
  138. {
  139. int old = m_WParser->GetAlign();
  140. wxHtmlContainerCell *c = m_WParser->GetContainer();
  141. m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
  142. if (c->GetFirstChild() != NULL)
  143. {
  144. m_WParser->CloseContainer();
  145. m_WParser->OpenContainer();
  146. }
  147. else
  148. c->SetAlignHor(wxHTML_ALIGN_CENTER);
  149. if (tag.HasEnding())
  150. {
  151. ParseInner(tag);
  152. m_WParser->SetAlign(old);
  153. if (c->GetFirstChild() != NULL)
  154. {
  155. m_WParser->CloseContainer();
  156. m_WParser->OpenContainer();
  157. }
  158. else
  159. c->SetAlignHor(old);
  160. return true;
  161. }
  162. else return false;
  163. }
  164. TAG_HANDLER_END(CENTER)
  165. TAG_HANDLER_BEGIN(DIV, "DIV")
  166. TAG_HANDLER_CONSTR(DIV) { }
  167. TAG_HANDLER_PROC(tag)
  168. {
  169. if(tag.HasParam(wxT("STYLE")))
  170. {
  171. if(tag.GetParam(wxT("STYLE")).IsSameAs(wxT("PAGE-BREAK-BEFORE:ALWAYS"), false))
  172. {
  173. m_WParser->CloseContainer();
  174. m_WParser->OpenContainer()->InsertCell(new wxHtmlPageBreakCell);
  175. m_WParser->CloseContainer();
  176. m_WParser->OpenContainer();
  177. return false;
  178. }
  179. else
  180. {
  181. // Treat other STYLE parameters here when they're supported.
  182. return false;
  183. }
  184. }
  185. else if(tag.HasParam(wxT("ALIGN")))
  186. {
  187. int old = m_WParser->GetAlign();
  188. wxHtmlContainerCell *c = m_WParser->GetContainer();
  189. if (c->GetFirstChild() != NULL)
  190. {
  191. m_WParser->CloseContainer();
  192. m_WParser->OpenContainer();
  193. c = m_WParser->GetContainer();
  194. c->SetAlign(tag);
  195. m_WParser->SetAlign(c->GetAlignHor());
  196. }
  197. else
  198. {
  199. c->SetAlign(tag);
  200. m_WParser->SetAlign(c->GetAlignHor());
  201. }
  202. ParseInner(tag);
  203. m_WParser->SetAlign(old);
  204. if (c->GetFirstChild() != NULL)
  205. {
  206. m_WParser->CloseContainer();
  207. m_WParser->OpenContainer();
  208. }
  209. else
  210. c->SetAlignHor(old);
  211. return true;
  212. }
  213. else
  214. {
  215. // Same as BR
  216. int al = m_WParser->GetContainer()->GetAlignHor();
  217. wxHtmlContainerCell *c;
  218. m_WParser->CloseContainer();
  219. c = m_WParser->OpenContainer();
  220. c->SetAlignHor(al);
  221. c->SetAlign(tag);
  222. c->SetMinHeight(m_WParser->GetCharHeight());
  223. return false;
  224. }
  225. }
  226. TAG_HANDLER_END(DIV)
  227. TAG_HANDLER_BEGIN(TITLE, "TITLE")
  228. TAG_HANDLER_CONSTR(TITLE) { }
  229. TAG_HANDLER_PROC(tag)
  230. {
  231. wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface();
  232. if (winIface)
  233. {
  234. wxString title(tag.GetBeginIter(), tag.GetEndIter1());
  235. #if !wxUSE_UNICODE
  236. const wxFontEncoding enc = m_WParser->GetInputEncoding();
  237. if ( enc != wxFONTENCODING_DEFAULT )
  238. {
  239. // need to convert to the current one
  240. title = wxString(title.wc_str(wxCSConv(enc)), wxConvLocal);
  241. }
  242. #endif // !wxUSE_UNICODE
  243. title = m_WParser->GetEntitiesParser()->Parse(title);
  244. winIface->SetHTMLWindowTitle(title);
  245. }
  246. return true;
  247. }
  248. TAG_HANDLER_END(TITLE)
  249. TAG_HANDLER_BEGIN(BODY, "BODY")
  250. TAG_HANDLER_CONSTR(BODY) { }
  251. TAG_HANDLER_PROC(tag)
  252. {
  253. wxColour clr;
  254. if (tag.GetParamAsColour(wxT("TEXT"), &clr))
  255. {
  256. m_WParser->SetActualColor(clr);
  257. m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(clr));
  258. }
  259. if (tag.GetParamAsColour(wxT("LINK"), &clr))
  260. m_WParser->SetLinkColor(clr);
  261. wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface();
  262. // the rest of this function requires a window:
  263. if ( !winIface )
  264. return false;
  265. if (tag.HasParam(wxT("BACKGROUND")))
  266. {
  267. wxFSFile *fileBgImage = m_WParser->OpenURL
  268. (
  269. wxHTML_URL_IMAGE,
  270. tag.GetParam(wxT("BACKGROUND"))
  271. );
  272. if ( fileBgImage )
  273. {
  274. wxInputStream *is = fileBgImage->GetStream();
  275. if ( is )
  276. {
  277. wxImage image(*is);
  278. if ( image.IsOk() )
  279. winIface->SetHTMLBackgroundImage(image);
  280. }
  281. delete fileBgImage;
  282. }
  283. }
  284. if (tag.GetParamAsColour(wxT("BGCOLOR"), &clr))
  285. {
  286. m_WParser->GetContainer()->InsertCell(
  287. new wxHtmlColourCell(clr, wxHTML_CLR_BACKGROUND));
  288. winIface->SetHTMLBackgroundColour(clr);
  289. }
  290. return false;
  291. }
  292. TAG_HANDLER_END(BODY)
  293. TAG_HANDLER_BEGIN(BLOCKQUOTE, "BLOCKQUOTE")
  294. TAG_HANDLER_CONSTR(BLOCKQUOTE) { }
  295. TAG_HANDLER_PROC(tag)
  296. {
  297. wxHtmlContainerCell *c;
  298. m_WParser->CloseContainer();
  299. c = m_WParser->OpenContainer();
  300. if (c->GetAlignHor() == wxHTML_ALIGN_RIGHT)
  301. c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_RIGHT);
  302. else
  303. c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT);
  304. c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
  305. m_WParser->OpenContainer();
  306. ParseInner(tag);
  307. c = m_WParser->CloseContainer();
  308. c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_BOTTOM);
  309. m_WParser->CloseContainer();
  310. m_WParser->OpenContainer();
  311. return true;
  312. }
  313. TAG_HANDLER_END(BLOCKQUOTE)
  314. TAG_HANDLER_BEGIN(SUBSUP, "SUB,SUP")
  315. TAG_HANDLER_PROC(tag)
  316. {
  317. bool issub = (tag.GetName() == wxT("SUB"));
  318. wxHtmlScriptMode oldmode = m_WParser->GetScriptMode();
  319. int oldbase = m_WParser->GetScriptBaseline();
  320. int oldsize = m_WParser->GetFontSize();
  321. wxHtmlContainerCell *cont = m_WParser->GetContainer();
  322. wxHtmlCell *c = cont->GetLastChild();
  323. m_WParser->SetScriptMode(issub ? wxHTML_SCRIPT_SUB : wxHTML_SCRIPT_SUP);
  324. m_WParser->SetScriptBaseline(
  325. oldbase + c ? c->GetScriptBaseline() : 0);
  326. // select smaller font
  327. m_WParser->SetFontSize(m_WParser->GetFontSize()-2);
  328. cont->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
  329. ParseInner(tag);
  330. // restore font size
  331. m_WParser->SetFontSize(oldsize);
  332. m_WParser->GetContainer()->InsertCell(
  333. new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
  334. // restore base and alignment
  335. m_WParser->SetScriptBaseline(oldbase);
  336. m_WParser->SetScriptMode(oldmode);
  337. return true;
  338. }
  339. TAG_HANDLER_END(SUBSUP)
  340. // Tag handler for tags that we have to ignore, otherwise non-text data
  341. // would show up as text:
  342. TAG_HANDLER_BEGIN(DoNothing, "SCRIPT")
  343. TAG_HANDLER_CONSTR(DoNothing) { }
  344. TAG_HANDLER_PROC(WXUNUSED(tag))
  345. {
  346. return true;
  347. }
  348. TAG_HANDLER_END(DoNothing)
  349. TAGS_MODULE_BEGIN(Layout)
  350. TAGS_MODULE_ADD(P)
  351. TAGS_MODULE_ADD(BR)
  352. TAGS_MODULE_ADD(CENTER)
  353. TAGS_MODULE_ADD(DIV)
  354. TAGS_MODULE_ADD(TITLE)
  355. TAGS_MODULE_ADD(BODY)
  356. TAGS_MODULE_ADD(BLOCKQUOTE)
  357. TAGS_MODULE_ADD(SUBSUP)
  358. TAGS_MODULE_ADD(DoNothing)
  359. TAGS_MODULE_END(Layout)
  360. #endif