1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2006,2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
20 #include "htmlformatter.h"
\r
22 CHTMLFormatter::CHTMLFormatter(void)
\r
26 CHTMLFormatter::~CHTMLFormatter(void)
\r
30 CSize CHTMLFormatter::DrawHTML(CDC * pDC, CRect rect, CString str, LOGFONT font, BOOL bCalculate /* = FALSE */)
\r
32 CUIntArray nLengthLines;
\r
35 STATEMACHINE nState = BEGIN_TAG;
\r
36 int nAlign = ALIGN_LEFT;
\r
37 BOOL bCloseTag = FALSE;
\r
39 m_arLinkRects.RemoveAll();
\r
40 m_arLinkURLs.RemoveAll();
\r
47 CPoint pt = rect.TopLeft();
\r
51 COLORREF crText = pDC->GetTextColor();
\r
52 COLORREF crBg = pDC->GetBkColor();
\r
55 memcpy(&lf, &font, sizeof(LOGFONT));
\r
58 tempFont.CreateFontIndirect(&lf);
\r
60 CFont * pOldFont = pDC->SelectObject(&tempFont);
\r
62 TEXTMETRIC textMetric;
\r
63 pDC->GetTextMetrics(&textMetric);
\r
64 int nHeight = textMetric.tmHeight;
\r
65 int nWidth = textMetric.tmAveCharWidth;
\r
67 CString strTag = _T("");
\r
68 CString strText = _T("");
\r
72 linkRect.SetRectEmpty();
\r
77 int nTemp = 0; //the temporary variable
\r
78 BOOL bFirstOutput = TRUE;
\r
80 //iterate through all characters of the string
\r
81 for (int i = 0; i <= str.GetLength(); i++)
\r
83 if (i < str.GetLength())
\r
85 //Searches the command and parameters in the string
\r
89 //waiting for the begin of a tag (<tag>), newline ('\n' or '\r') or tab ('\t')
\r
90 switch (str.GetAt(i))
\r
93 nState = TEXT_TAG; //statemachine to 'waiting for the tag'
\r
94 bCloseTag = FALSE; //opening bracket
\r
108 strText += str.GetAt(i);
\r
113 //get the tag itself (until the closing bracket ('>'))
\r
114 switch (str.GetAt(i))
\r
117 if (strTag.IsEmpty())
\r
118 bCloseTag = TRUE; //found the char's cancel tag
\r
121 if (strTag.IsEmpty())
\r
123 nState = BEGIN_TAG;
\r
124 strText += str.GetAt(i);
\r
126 else strTag += str.GetAt(i);
\r
133 if (strTag.CompareNoCase(_T("b"))==0)
\r
139 else if (strTag.CompareNoCase(_T("i")) == 0)
\r
145 else if (strTag.CompareNoCase(_T("s")) == 0)
\r
151 else if (strTag.CompareNoCase(_T("u")) == 0)
\r
157 else if (strTag.CompareNoCase(_T("t")) == 0)
\r
162 nState = BEGIN_NUMBER;
\r
164 else if (strTag.CompareNoCase(_T("ct")) == 0)
\r
166 //Color of the text
\r
169 nState = BEGIN_NUMBER;
\r
171 else if (strTag.CompareNoCase(_T("cb")) == 0)
\r
173 //Color of the background
\r
176 nState = BEGIN_NUMBER;
\r
178 else if (strTag.CompareNoCase(_T("al")) == 0)
\r
181 nAlign = ALIGN_LEFT;
\r
184 else if (strTag.CompareNoCase(_T("ac")) == 0)
\r
188 nAlign = bCloseTag ? ALIGN_LEFT : ALIGN_CENTER;
\r
191 else if (strTag.CompareNoCase(_T("ar")) == 0)
\r
195 nAlign = bCloseTag ? ALIGN_LEFT : ALIGN_RIGHT;
\r
198 else if (strTag.CompareNoCase(_T("hr")) == 0)
\r
201 nCmd = HORZ_LINE_PERCENT;
\r
203 nState = BEGIN_NUMBER;
\r
205 else if (strTag.CompareNoCase(_T("a")) == 0)
\r
209 nState = BEGIN_URL; //wait for '='
\r
211 else nState = END_TAG; //Unknown tag
\r
214 strTag += str.GetAt(i);
\r
219 //waiting for the end of the tag
\r
220 if (str.GetAt(i) == _T('>'))
\r
221 nState = BEGIN_TAG;
\r
224 //waiting for the start of a number
\r
225 if (str.GetAt(i) == _T('='))
\r
228 nState = TEXT_NUMBER;
\r
230 else if (str.GetAt(i) == _T('>'))
\r
231 nState = BEGIN_TAG; //not a number
\r
234 //waiting for the start of a number
\r
235 if (str.GetAt(i) == _T('='))
\r
240 else if (str.GetAt(i) == _T('>'))
\r
241 nState = BEGIN_TAG; //not a url
\r
244 //waiting for a number string
\r
245 switch (str.GetAt(i))
\r
249 //intended fall through!
\r
251 //Gets the real number from the string
\r
252 if (!strTag.IsEmpty())
\r
253 nParam = _tcstoul(strTag, 0, 0);
\r
257 strTag += str.GetAt(i);
\r
262 //waiting for a url
\r
263 switch (str.GetAt(i))
\r
267 if (!strTag.IsEmpty())
\r
268 m_arLinkURLs.Add(strTag);
\r
272 strTag += str.GetAt(i);
\r
275 } // switch (nState)
\r
279 //Immitates new line at the end of the string
\r
280 nState = BEGIN_TAG;
\r
285 if ((nState == BEGIN_TAG) && (nCmd != NONE))
\r
287 //New Command with full parameters
\r
288 if (!strText.IsEmpty())
\r
295 ptCur.x = pt.x + (rect.Width() - nLengthLines.GetAt(nLine)) / 2;
\r
298 ptCur.x = pt.x + rect.Width() - nLengthLines.GetAt(nLine);
\r
303 pDC->TextOut(ptCur.x, ptCur.y, strText);
\r
304 CSize s = pDC->GetTextExtent(strText);
\r
305 linkRect.left = ptCur.x;
\r
306 linkRect.top = ptCur.y;
\r
307 linkRect.right = linkRect.left + s.cx;
\r
308 linkRect.bottom = linkRect.top + s.cy;
\r
311 bFirstOutput = FALSE;
\r
321 m_arLinkRects.Add(linkRect);
\r
322 linkRect.SetRectEmpty();
\r
327 pDC->SelectObject(pOldFont);
\r
328 tempFont.DeleteObject();
\r
329 lf.lfWeight = font.lfWeight;
\r
333 if (lf.lfWeight > FW_BLACK)
\r
334 lf.lfWeight = FW_BLACK;
\r
336 tempFont.CreateFontIndirect(&lf);
\r
337 pDC->SelectObject(&tempFont);
\r
341 pDC->SelectObject(pOldFont);
\r
342 tempFont.DeleteObject();
\r
343 lf.lfItalic = bCloseTag ? FALSE : TRUE;
\r
344 tempFont.CreateFontIndirect(&lf);
\r
345 pDC->SelectObject(&tempFont);
\r
349 pDC->SelectObject(pOldFont);
\r
350 tempFont.DeleteObject();
\r
351 lf.lfStrikeOut = bCloseTag ? FALSE : TRUE;
\r
352 tempFont.CreateFontIndirect(&lf);
\r
353 pDC->SelectObject(&tempFont);
\r
357 pDC->SelectObject(pOldFont);
\r
358 tempFont.DeleteObject();
\r
359 lf.lfUnderline = bCloseTag ? FALSE : TRUE;
\r
360 tempFont.CreateFontIndirect(&lf);
\r
361 pDC->SelectObject(&tempFont);
\r
364 //Color of the text
\r
365 pDC->SetTextColor((COLORREF)nParam);
\r
368 //Color of the background
\r
369 pDC->SetBkColor((COLORREF)nParam);
\r
370 pDC->SetBkMode(bCloseTag ? TRANSPARENT : OPAQUE);
\r
372 case HORZ_LINE_PERCENT:
\r
373 //Horizontal line with percent length
\r
376 percent.SetAt(nLine, percent.GetAt(nLine) + nParam);
\r
379 else nParam = ::MulDiv(rect.Width(), nParam, 100);
\r
381 //Horizontal line with absolute length
\r
382 //If text to output is exist
\r
388 ptCur.x = pt.x + (rect.Width() - nLengthLines.GetAt(nLine)) / 2;
\r
391 ptCur.x = pt.x + rect.Width() - nLengthLines.GetAt(nLine);
\r
395 DrawHorzLine(pDC, ptCur.x, ptCur.x + nParam, ptCur.y + nHeight / 2);
\r
397 bFirstOutput = FALSE;
\r
403 sz.cx = max(sz.cx, ptCur.x - pt.x);
\r
404 nLengthLines.Add(ptCur.x - pt.x); //Adds the real length of the lines
\r
405 ptCur.y += nHeight * nParam;
\r
408 bFirstOutput = TRUE;
\r
415 nTemp = (ptCur.x - pt.x) % (nWidth * 4);
\r
419 ptCur.x += (nWidth * 4) - nTemp;
\r
422 ptCur.x += (nParam * nWidth * 4);
\r
425 //Resets the last command
\r
431 //Gets real height of the tooltip
\r
432 sz.cy = ptCur.y - pt.y;
\r
434 pDC->SelectObject(pOldFont);
\r
435 tempFont.DeleteObject();
\r
437 //Adds the percent's length to the line's length
\r
438 for (int i = 0; i < percent.GetSize(); i++)
\r
440 if (percent.GetAt(i))
\r
441 nLengthLines.SetAt(i, nLengthLines.GetAt(i) + ::MulDiv(percent.GetAt(i), sz.cx, 100));
\r
447 void CHTMLFormatter::DrawHorzLine(CDC * pDC, int xStart, int xEnd, int y)
\r
449 CPen pen(PS_SOLID, 1, pDC->GetTextColor());
\r
450 CPen * penOld = pDC->SelectObject(&pen);
\r
451 pDC->MoveTo(xStart, y);
\r
452 pDC->LineTo(xEnd, y);
\r
453 pDC->SelectObject(penOld);
\r
454 pen.DeleteObject();
\r
457 BOOL CHTMLFormatter::IsPointOverALink(CPoint pt)
\r
460 for (int i=0; i<m_arLinkRects.GetCount(); i++)
\r
462 rect = m_arLinkRects.GetAt(i);
\r
463 if (rect.PtInRect(pt))
\r
469 CString CHTMLFormatter::GetLinkForPoint(CPoint pt)
\r
472 for (int i=0; i<m_arLinkRects.GetCount(); i++)
\r
474 rect = m_arLinkRects.GetAt(i);
\r
475 if (rect.PtInRect(pt))
\r
477 return m_arLinkURLs.GetAt(i);
\r