Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGHtmlLayout.cxx
Go to the documentation of this file.
1// $Id: TGHtmlLayout.cxx,v 1.1 2007/05/04 17:07:01 brun Exp $
2// Author: Valeriy Onuchin 03/05/2007
3
4/**************************************************************************
5
6 HTML widget for xclass. Based on tkhtml 1.28
7 Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
8 Copyright (C) 2002-2003 Hector Peraza.
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
19
20 You should have received a copy of the GNU Library General Public
21 License along with this library; if not, write to the Free
22 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24**************************************************************************/
25
26// This file contains the code used to position elements of the
27// HTML file on the screen.
28
29#include <stdlib.h>
30#include <string.h>
31
32#include "TGHtml.h"
33
34
35////////////////////////////////////////////////////////////////////////////////
36/// Html Layout Context constructor.
37
39{
40 fPStart = 0;
41 fPEnd = 0;
42 fLeftMargin = 0;
43 fRightMargin = 0;
44 fHtml = 0;
45 fLeft = 0;
46 fRight = 0;
47 fMaxX = 0;
48 fMaxY = 0;
49 fPageWidth = 0;
50 Reset();
51}
52
53////////////////////////////////////////////////////////////////////////////////
54/// Reset the layout context.
55
57{
58 fHeadRoom = 0;
59 fTop = 0;
60 fBottom = 0;
63}
64
65////////////////////////////////////////////////////////////////////////////////
66/// Push a new margin onto the given margin stack.
67///
68/// If the "bottom" parameter is non-negative, then this margin will
69/// automatically expire for all text that is placed below the y-coordinate
70/// given by "bottom". This feature is used for <IMG ALIGN=left> and <IMG
71/// ALIGN=right> kinds of markup. It allows text to flow around an image.
72///
73/// If "bottom" is negative, then the margin stays in force until it is
74/// explicitly canceled by a call to PopMargin().
75///
76/// ppMargin - The margin stack onto which to push
77/// indent - The indentation for the new margin
78/// mbottom - The margin expires at this Y coordinate
79/// tag - Markup that will cancel this margin
80
82 int indent, int mbottom, int tag)
83{
84 SHtmlMargin_t *pNew = new SHtmlMargin_t;
85 pNew->fPNext = *ppMargin;
86 if (pNew->fPNext) {
87 pNew->fIndent = indent + pNew->fPNext->fIndent;
88 } else {
89 pNew->fIndent = indent;
90 }
91 pNew->fBottom = mbottom;
92 pNew->fTag = tag;
93 *ppMargin = pNew;
94}
95
96////////////////////////////////////////////////////////////////////////////////
97/// Pop one margin off of the given margin stack.
98
100{
101 if (*ppMargin) {
102 SHtmlMargin_t *pOld = *ppMargin;
103 *ppMargin = pOld->fPNext;
104 delete pOld;
105 }
106}
107
108////////////////////////////////////////////////////////////////////////////////
109/// Pop as many margins as necessary until the margin that was
110/// created with "tag" is popped off. Update the layout context
111/// to move past obstacles, if necessary.
112///
113/// If there are some margins on the stack that contain non-negative
114/// bottom fields, that means there are some obstacles that we have
115/// not yet cleared. If these margins get popped off the stack,
116/// then we have to be careful to advance the 'bottom' value so
117/// that the next line of text will clear the obstacle.
118
120{
121 int bot = -1;
122 int oldTag;
123 SHtmlMargin_t *pM;
124
125 for (pM = *ppMargin; pM && pM->fTag != tag; pM = pM->fPNext) {}
126 if (pM == 0) {
127 // No matching margin is found. Do nothing.
128 return;
129 }
130 while ((pM = *ppMargin) != 0) {
131 if (pM->fBottom > bot) bot = pM->fBottom;
132 oldTag = pM->fTag;
133 PopOneMargin(ppMargin);
134 if (oldTag == tag) break;
135 }
136 if (fBottom < bot) {
137 fHeadRoom += bot - fBottom;
138 fBottom = bot;
139 }
140}
141
142////////////////////////////////////////////////////////////////////////////////
143/// Pop all expired margins from the stack.
144///
145/// An expired margin is one with a non-negative bottom parameter
146/// that is less than the value "y". "y" is the Y-coordinate of
147/// the top edge the next line of text to by positioned. What this
148/// function does is check to see if we have cleared any obstacles
149/// (an obstacle is an <IMG ALIGN=left> or <IMG ALIGN=right>) and
150/// expands the margins if we have.
151
153{
154 while (*ppMarginStack && (**ppMarginStack).fBottom >= 0 &&
155 (**ppMarginStack).fBottom <= y) {
156 PopOneMargin(ppMarginStack);
157 }
158}
159
160////////////////////////////////////////////////////////////////////////////////
161/// Clear a margin stack to reclaim memory. This routine just blindly
162/// pops everything off the stack. Typically used when the screen is
163/// cleared or the widget is deleted, etc.
164
166{
167 while (*ppMargin) PopOneMargin(ppMargin);
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// This routine gathers as many tokens as will fit on one line.
172///
173/// The candidate tokens begin with fPStart and go thru the end of
174/// the list or to fPEnd, whichever comes first. The first token
175/// at the start of the next line is returned. NULL is returned if
176/// we exhaust data.
177///
178/// "width" is the maximum allowed width of the line. The actual
179/// width is returned in *actualWidth. The actual width does not
180/// include any trailing spaces. Sometimes the actual width will
181/// be greater than the maximum width. This will happen, for example,
182/// for text enclosed in <pre>..</pre> that has lines longer than
183/// the width of the page.
184///
185/// If the list begins with text, at least one token is returned,
186/// even if that one token is longer than the allowed line length.
187/// But if the list begins with some kind of break markup (possibly
188/// preceded by white space) then the returned list may be empty.
189///
190/// The "x" coordinates of all elements are set assuming that the line
191/// begins at 0. The calling routine should adjust these coordinates
192/// to position the line horizontally. (The FixLine() procedure does
193/// this.) Note that the "x" coordinate of <li> elements will be negative.
194/// Text within <dt>..</dt> might also have a negative "x" coordinate.
195/// But in no case will the x coordinate every be less than "minX".
196///
197/// p_start - First token on new line
198/// p_end - End of line. Might be NULL
199/// width - How much space is on this line
200/// minX - The minimum value of the X coordinate
201/// actualWidth - Return space actually required
202
204 TGHtmlElement *p_end, int width, int minX, int *actualWidth)
205{
206 int x; // Current X coordinate
207 int spaceWanted = 0; // Add this much space before next token
208 TGHtmlElement *p; // For looping over tokens
209 TGHtmlElement *lastBreak = 0; // Last line-break opportunity
210 int isEmpty = 1; // True if link contains nothing
211 int origin; // Initial value of "x"
212
213 *actualWidth = 0;
214 p = p_start;
215 while (p && p != p_end && (p->fStyle.fFlags & STY_Invisible) != 0) {
216 p = p->fPNext;
217 }
218 if (p && p->fStyle.fFlags & STY_DT) {
219 origin = -HTML_INDENT;
220 } else {
221 origin = 0;
222 }
223 x = origin;
224 if (x < minX) x = minX;
225 if (p && p != p_end && p->fType == Html_LI) {
226 TGHtmlLi *li = (TGHtmlLi *) p;
227 li->fX = x - HTML_INDENT / 3;
228 if (li->fX - (HTML_INDENT * 2) / 3 < minX) {
229 x += minX - li->fX + (HTML_INDENT * 2) / 3;
230 li->fX = minX + (HTML_INDENT * 2) / 3;
231 }
232 isEmpty = 0;
233 *actualWidth = 1;
234 p = p->fPNext;
235 while (p && (p->fType == Html_Space || p->fType == Html_P)) {
236 p = p->fPNext;
237 }
238 }
239 // coverity[dead_error_line]
240 for (; p && p != p_end; p = p ? p->fPNext : 0) {
241 if (p->fStyle.fFlags & STY_Invisible) continue;
242 switch (p->fType) {
243 case Html_Text: {
245 text->fX = x + spaceWanted;
246 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
247 if (lastBreak && x + spaceWanted + text->fW > width)
248 return lastBreak;
249 }
250// TRACE(HtmlTrace_GetLine2, ("Place token %s at x=%d w=%d\n",
251// HtmlTokenName(p), text->fX, text->fW));
252 x += text->fW + spaceWanted;
253 isEmpty = 0;
254 spaceWanted = 0;
255 break;
256 }
257
258 case Html_Space: {
260 if (p->fStyle.fFlags & STY_Preformatted) {
261 if (p->fFlags & HTML_NewLine) {
262 *actualWidth = (x <= 0) ? 1 : x;
263 return p->fPNext;
264 }
265 x += space->fW * p->fCount;
266 } else {
267 int w;
268 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
269 lastBreak = p->fPNext;
270 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
271 }
272 w = space->fW;
273 if (spaceWanted < w && x > origin) spaceWanted = w;
274 }
275 break;
276 }
277
278 case Html_IMG: {
280 switch (image->fAlign) {
281 case IMAGE_ALIGN_Left:
283 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
284 return p;
285 default:
286 break;
287 }
288 image->fX = x + spaceWanted;
289 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
290 if (lastBreak && x + spaceWanted + image->fW > width) {
291 return lastBreak;
292 }
293 }
294// TRACE(HtmlTrace_GetLine2, ("Place in-line image %s at x=%d w=%d\n",
295// HtmlTokenName(p), p->image.x, p->image.w));
296 x += image->fW + spaceWanted;
297 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
298 lastBreak = p->fPNext;
299 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
300 }
301 spaceWanted = 0;
302 isEmpty = 0;
303 break;
304 }
305
306 case Html_APPLET:
307 case Html_EMBED:
308 case Html_INPUT:
309 case Html_SELECT:
310 case Html_TEXTAREA: {
311 TGHtmlInput *input = (TGHtmlInput *) p;
312 input->fX = x + spaceWanted + input->fPadLeft;
313 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
314 if (lastBreak && x + spaceWanted + input->fW > width) {
315 return lastBreak;
316 }
317 }
318// TRACE(HtmlTrace_GetLine2, ("Place token %s at x=%d w=%d\n",
319// HtmlTokenName(p), p->input.x, p->input.w));
320 x = input->fX + input->fW;
321 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
322 lastBreak = p->fPNext;
323 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
324 }
325 spaceWanted = 0;
326 isEmpty = 0;
327 break;
328 }
329
330 case Html_EndTEXTAREA: {
331 TGHtmlRef *ref = (TGHtmlRef *) p;
332 if (ref->fPOther) {
333 // fHtml->ResetTextarea(ref->fPOther);
334 }
335 break;
336 }
337
338 case Html_DD: {
339 TGHtmlRef *ref = (TGHtmlRef *) p;
340 if (ref->fPOther == 0) break;
341 if (((TGHtmlListStart *)ref->fPOther)->fCompact == 0 ||
342 x + spaceWanted >= 0) {
343 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
344 return p;
345 }
346 x = 0;
347 spaceWanted = 0;
348 break;
349 }
350
351 case Html_WBR:
352 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
353 if (x + spaceWanted >= width) {
354 return p->fPNext;
355 } else {
356 lastBreak = p->fPNext;
357 }
358 break;
359
360 case Html_ADDRESS:
361 case Html_EndADDRESS:
362 case Html_BLOCKQUOTE:
364 case Html_BODY:
365 case Html_EndBODY:
366 case Html_BR:
367 case Html_CAPTION:
368 case Html_EndCAPTION:
369 case Html_CENTER:
370 case Html_EndCENTER:
371 case Html_EndDD:
372 case Html_DIV:
373 case Html_EndDIV:
374 case Html_DL:
375 case Html_EndDL:
376 case Html_DT:
377 case Html_H1:
378 case Html_EndH1:
379 case Html_H2:
380 case Html_EndH2:
381 case Html_H3:
382 case Html_EndH3:
383 case Html_H4:
384 case Html_EndH4:
385 case Html_H5:
386 case Html_EndH5:
387 case Html_H6:
388 case Html_EndH6:
389 case Html_EndHTML:
390 case Html_HR:
391 case Html_LI:
392 case Html_LISTING:
393 case Html_EndLISTING:
394 case Html_MENU:
395 case Html_EndMENU:
396 case Html_OL:
397 case Html_EndOL:
398 case Html_P:
399 case Html_EndP:
400 case Html_PRE:
401 case Html_EndPRE:
402 case Html_TABLE:
403 case Html_EndTABLE:
404 case Html_TD:
405 case Html_EndTD:
406 case Html_TH:
407 case Html_EndTH:
408 case Html_TR:
409 case Html_EndTR:
410 case Html_UL:
411 case Html_EndUL:
412 case Html_EndFORM:
413 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
414 return p;
415
416 default:
417 break;
418 }
419 }
420 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
421
422 return p;
423}
424
425////////////////////////////////////////////////////////////////////////////////
426/// Set the y coordinate for every anchor in the given list
427
429{
430 while (p && p != p_end) {
431 if (p->fType == Html_A) ((TGHtmlAnchor *)p)->fY = y;
432 p = p->fPNext;
433 }
434}
435
436////////////////////////////////////////////////////////////////////////////////
437/// This routine computes the X and Y coordinates for all elements of
438/// a line that has been gathered using GetLine() above. It also figures
439/// the ascent and descent for in-line images.
440///
441/// The value returned is the Y coordinate of the bottom edge of the
442/// new line. The X coordinates are computed by adding the left margin
443/// plus any extra space needed for centering or right-justification.
444///
445/// p_start - Start of tokens for this line
446/// p_end - First token past end of this line. Maybe NULL
447/// mbottom - Put the top of this line here
448/// width - This is the space available to the line
449/// actualWidth - This is the actual width needed by the line
450/// lMargin - The current left margin
451/// max_x - Write maximum X coordinate of ink here
452
454 TGHtmlElement *p_end, int mbottom, int width,
455 int actualWidth, int lMargin, int *max_x)
456{
457 int dx; // Amount by which to increase all X coordinates
458 int maxAscent; // Maximum height above baseline
459 int maxTextAscent; // Maximum height above baseline for text
460 int maxDescent; // Maximum depth below baseline
461 int ascent, descent; // Computed ascent and descent for one element
462 TGHtmlElement *p; // For looping
463 int y; // Y coordinate of the baseline
464 int dy2center; // Distance from baseline to text font center
465 int max = 0;
466
467 if (actualWidth > 0) {
468 for (p = p_start; p && p != p_end && p->fType != Html_Text; p = p->fPNext) {}
469 if (p == p_end || p == 0) p = p_start;
470 maxAscent = maxTextAscent = 0;
471 for (p = p_start; p && p != p_end; p = p->fPNext) {
472 int ss;
473 if (p->fStyle.fAlign == ALIGN_Center) {
474 dx = lMargin + (width - actualWidth) / 2;
475 } else if (p->fStyle.fAlign == ALIGN_Right) {
476 dx = lMargin + (width - actualWidth);
477 } else {
478 dx = lMargin;
479 }
480 if (dx < 0) dx = 0;
481 if (p->fStyle.fFlags & STY_Invisible) continue;
482 switch (p->fType) {
483 case Html_Text: {
485 text->fX += dx;
486 max = text->fX + text->fW;
487 ss = p->fStyle.fSubscript;
488 if (ss > 0) {
489 int ascent2 = text->fAscent;
490 int delta = (ascent2 + text->fDescent) * ss / 2;
491 ascent2 += delta;
492 text->fY = -delta;
493 if (ascent2 > maxAscent) maxAscent = ascent2;
494 if (ascent2 > maxTextAscent) maxTextAscent = ascent2;
495 } else if (ss < 0) {
496 int descent2 = text->fDescent;
497 int delta = (descent2 + text->fAscent) * (-ss) / 2;
498 descent2 += delta;
499 text->fY = delta;
500 } else {
501 text->fY = 0;
502 if (text->fAscent > maxAscent) maxAscent = text->fAscent;
503 if (text->fAscent > maxTextAscent) maxTextAscent = text->fAscent;
504 }
505 break;
506 }
507
508 case Html_Space: {
510 if (space->fAscent > maxAscent) maxAscent = space->fAscent;
511 break;
512 }
513
514 case Html_LI: {
515 TGHtmlLi *li = (TGHtmlLi *) p;
516 li->fX += dx;
517 if (li->fX > max) max = li->fX;
518 break;
519 }
520
521 case Html_IMG: {
523 image->fX += dx;
524 max = image->fX + image->fW;
525 switch (image->fAlign) {
527 image->fDescent = image->fH / 2;
528 image->fAscent = image->fH - image->fDescent;
529 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
530 break;
531
533 dy2center = (image->fTextDescent - image->fTextAscent) / 2;
534 image->fDescent = image->fH / 2 + dy2center;
535 image->fAscent = image->fH - image->fDescent;
536 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
537 break;
538
540 image->fDescent = 0;
541 image->fAscent = image->fH;
542 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
543 break;
544
546 image->fDescent = image->fTextDescent;
547 image->fAscent = image->fH - image->fDescent;
548 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
549 break;
550
551 default:
552 break;
553 }
554 break;
555 }
556
557 case Html_TABLE:
558 break;
559
560 case Html_TEXTAREA:
561 case Html_INPUT:
562 case Html_SELECT:
563 case Html_EMBED:
564 case Html_APPLET: {
565 TGHtmlInput *input = (TGHtmlInput *) p;
566 input->fX += dx;
567 max = input->fX + input->fW;
568 dy2center = (input->fTextDescent - input->fTextAscent) / 2;
569 input->fY = dy2center - input->fH / 2;
570 ascent = -input->fY;
571 if (ascent > maxAscent) maxAscent = ascent;
572 break;
573 }
574
575 default:
576 // Shouldn't happen
577 break;
578 }
579 }
580
581 *max_x = max;
582 y = maxAscent + mbottom;
583 maxDescent = 0;
584
585 for (p = p_start; p && p != p_end; p = p->fPNext) {
586 if (p->fStyle.fFlags & STY_Invisible) continue;
587 switch (p->fType) {
588 case Html_Text: {
590 text->fY += y;
591 if (text->fDescent > maxDescent) maxDescent = text->fDescent;
592 break;
593 }
594
595 case Html_LI: {
596 TGHtmlLi *li = (TGHtmlLi *) p;
597 li->fY = y;
598 if (li->fDescent > maxDescent) maxDescent = li->fDescent;
599 break;
600 }
601
602 case Html_IMG: {
604 image->fY = y;
605 switch (image->fAlign) {
606 case IMAGE_ALIGN_Top:
607 image->fAscent = maxAscent;
608 image->fDescent = image->fH - maxAscent;
609 break;
610
612 image->fAscent = maxTextAscent;
613 image->fDescent = image->fH - maxTextAscent;
614 break;
615
616 default:
617 break;
618 }
619 if (image->fDescent > maxDescent) maxDescent = image->fDescent;
620 break;
621 }
622
623 case Html_TABLE:
624 break;
625
626 case Html_INPUT:
627 case Html_SELECT:
628 case Html_TEXTAREA:
629 case Html_APPLET:
630 case Html_EMBED: {
631 TGHtmlInput *input = (TGHtmlInput *) p;
632 descent = input->fY + input->fH;
633 input->fY += y;
634 if (descent > maxDescent) maxDescent = descent;
635 break;
636 }
637
638 default:
639 /* Shouldn't happen */
640 break;
641 }
642 }
643
644// TRACE(HtmlTrace_FixLine,
645// ("Setting baseline to %d. mbottom=%d ascent=%d descent=%d dx=%d\n",
646// y, mbottom, maxAscent, maxDescent, dx));
647
648 } else {
649 maxDescent = 0;
650 y = mbottom;
651 }
652
653 return y + maxDescent;
654}
655
656////////////////////////////////////////////////////////////////////////////////
657/// Increase the headroom to create a paragraph break at the current token
658
660{
661 int headroom;
662
663 if (p == 0) return;
664
665 if (p->fType == Html_Text) {
667 headroom = text->fAscent + text->fDescent;
668 } else if (p->fPNext && p->fPNext->fType == Html_Text) {
670 headroom = text->fAscent + text->fDescent;
671 } else {
672 //// headroom = 10;
673 FontMetrics_t fontMetrics;
674 TGFont *font;
675 font = fHtml->GetFont(p->fStyle.fFont);
676 if (font == 0) return;
677 font->GetFontMetrics(&fontMetrics);
678 headroom = fontMetrics.fDescent + fontMetrics.fAscent;
679 }
680 if (fHeadRoom < headroom && fBottom > fTop) fHeadRoom = headroom;
681}
682
683////////////////////////////////////////////////////////////////////////////////
684/// Compute the current margins for layout. Three values are returned:
685///
686/// *pY The top edge of the area in which we can put ink. This
687/// takes into account any requested headroom.
688///
689/// *pX The left edge of the inkable area. The takes into account
690/// any margin requests active at vertical position specified
691/// in pLC->bottom.
692///
693/// *pW The width of the inkable area. This takes into account
694/// an margin requests that are active at the vertical position
695/// pLC->bottom.
696///
697
698void TGHtmlLayoutContext::ComputeMargins(int *pX, int *pY, int *pW)
699{
700 int x, y, w;
701
702 y = fBottom + fHeadRoom;
705 w = fPageWidth - fRight;
706 if (fLeftMargin) {
708 } else {
709 x = fLeft;
710 }
711 w -= x;
713
714 *pX = x;
715 *pY = y;
716 *pW = w;
717}
718
719#define CLEAR_Left 0
720#define CLEAR_Right 1
721#define CLEAR_Both 2
722#define CLEAR_First 3
723////////////////////////////////////////////////////////////////////////////////
724/// Clear a wrap-around obstacle. The second option determines the
725/// precise behavior.
726///
727/// CLEAR_Left Clear all obstacles on the left.
728///
729/// CLEAR_Right Clear all obstacles on the right.
730///
731/// CLEAR_Both Clear all obstacles on both sides.
732///
733/// CLEAR_First Clear only the first obstacle on either side.
734
736{
737 int newBottom = fBottom;
738
741
742 switch (mode) {
743 case CLEAR_Both:
746 break;
747
748 case CLEAR_Left:
749 while (fLeftMargin && fLeftMargin->fBottom >= 0) {
750 if (newBottom < fLeftMargin->fBottom) {
751 newBottom = fLeftMargin->fBottom;
752 }
754 }
755 if (newBottom > fBottom + fHeadRoom) {
756 fHeadRoom = 0;
757 } else {
758 fHeadRoom = newBottom - fBottom;
759 }
760 fBottom = newBottom;
762 break;
763
764 case CLEAR_Right:
765 while (fRightMargin && fRightMargin->fBottom >= 0) {
766 if (newBottom < fRightMargin->fBottom) {
767 newBottom = fRightMargin->fBottom;
768 }
770 }
771 if (newBottom > fBottom + fHeadRoom) {
772 fHeadRoom = 0;
773 } else {
774 fHeadRoom = newBottom - fBottom;
775 }
776 fBottom = newBottom;
778 break;
779
780 case CLEAR_First:
781 if (fLeftMargin && fLeftMargin->fBottom >= 0) {
782 if (fRightMargin &&
784 if (newBottom < fRightMargin->fBottom) {
785 newBottom = fRightMargin->fBottom;
786 }
788 } else {
789 if (newBottom < fLeftMargin->fBottom) {
790 newBottom = fLeftMargin->fBottom;
791 }
793 }
794 } else if (fRightMargin && fRightMargin->fBottom >= 0) {
795 newBottom = fRightMargin->fBottom;
797 }
798 if (newBottom > fBottom + fHeadRoom) {
799 fHeadRoom = 0;
800 } else {
801 fHeadRoom = newBottom - fBottom;
802 }
803 fBottom = newBottom;
804 break;
805
806 default:
807 break;
808 }
809}
810
811////////////////////////////////////////////////////////////////////////////////
812/// Return the next markup type [TGHtmlElement::NextMarkupType]
813
815{
816 while ((p = p->fPNext)) {
817 if (p->IsMarkup()) return p->fType;
818 }
819 return Html_Unknown;
820}
821
822////////////////////////////////////////////////////////////////////////////////
823/// Break markup is any kind of markup that might force a line-break. This
824/// routine handles a single element of break markup and returns a pointer
825/// to the first element past that markup. If p doesn't point to break
826/// markup, then p is returned. If p is an incomplete table (a <TABLE>
827/// that lacks a </TABLE>), then NULL is returned.
828
830{
831 TGHtmlElement *fPNext = p->fPNext;
832 const char *z;
833 int x, y, w;
834
835 switch (p->fType) {
836 case Html_A:
837 ((TGHtmlAnchor *)p)->fY = fBottom;
838 break;
839
840 case Html_BLOCKQUOTE:
843 Paragraph(p);
844 break;
845
849 Paragraph(p);
850 break;
851
852 case Html_IMG: {
854 switch (image->fAlign) {
855 case IMAGE_ALIGN_Left:
856 ComputeMargins(&x, &y, &w);
857 image->fX = x;
858 image->fY = y;
859 image->fAscent = 0;
860 image->fDescent = image->fH;
861 PushMargin(&fLeftMargin, image->fW + 2, y + image->fH, 0);
862 if (fMaxY < y + image->fH) fMaxY = y + image->fH;
863 if (fMaxX < x + image->fW) fMaxX = x + image->fW;
864 break;
865
867 ComputeMargins(&x, &y, &w);
868 image->fX = x + w - image->fW;
869 image->fY = y;
870 image->fAscent = 0;
871 image->fDescent = image->fH;
872 PushMargin(&fRightMargin, image->fW + 2, y + image->fH, 0);
873 if (fMaxY < y + image->fH) fMaxY = y + image->fH;
874 if (fMaxX < x + image->fW) fMaxX = x + image->fW;
875 break;
876
877 default:
878 fPNext = p;
879 break;
880 }
881 break;
882 }
883
884 case Html_PRE:
885 // Skip space tokens thru the next newline.
886 while (fPNext->fType == Html_Space) {
887 TGHtmlElement *pThis = fPNext;
888 fPNext = fPNext->fPNext;
889 if (pThis->fFlags & HTML_NewLine) break;
890 }
891 Paragraph(p);
892 break;
893
894 case Html_UL:
895 case Html_MENU:
896 case Html_DIR:
897 case Html_OL:
898 if (((TGHtmlListStart *)p)->fCompact == 0) Paragraph(p);
900 break;
901
902 case Html_EndOL:
903 case Html_EndUL:
904 case Html_EndMENU:
905 case Html_EndDIR: {
906 TGHtmlRef *ref = (TGHtmlRef *) p;
907 if (ref->fPOther) {
909 if (!((TGHtmlListStart *)ref->fPOther)->fCompact) Paragraph(p);
910 }
911 break;
912 }
913
914 case Html_DL:
915 Paragraph(p);
917 break;
918
919 case Html_EndDL:
921 Paragraph(p);
922 break;
923
924 case Html_HR: {
925 int zl, wd;
926 TGHtmlHr *hr = (TGHtmlHr *) p;
927 hr->fIs3D = (p->MarkupArg("noshade", 0) == 0);
928 z = p->MarkupArg("size", 0);
929 if (z) {
930 int hrsz = atoi(z);
931 hr->fH = (hrsz < 0) ? 2 : hrsz;
932 } else {
933 hr->fH = 0;
934 }
935 if (hr->fH < 1) {
936 int relief = fHtml->GetRuleRelief();
937 if (hr->fIs3D &&
938 (relief == HTML_RELIEF_SUNKEN || relief == HTML_RELIEF_RAISED)) {
939 hr->fH = 3;
940 } else {
941 hr->fH = 2;
942 }
943 }
944 ComputeMargins(&x, &y, &w);
945 hr->fY = y + fHtml->GetRulePadding();
946 y += hr->fH + fHtml->GetRulePadding() * 2 + 1;
947 hr->fX = x;
948 z = p->MarkupArg("width", "100%");
949 zl = z ? strlen(z) : 0;
950 if (zl > 0 && z[zl-1] == '%') {
951 wd = (atoi(z) * w) / 100;
952 } else {
953 wd = z ? atoi(z) : w;
954 }
955 if (wd > w) wd = w;
956 hr->fW = wd;
957 switch (p->fStyle.fAlign) {
958 case ALIGN_Center:
959 case ALIGN_None:
960 hr->fX += (w - wd) / 2;
961 break;
962
963 case ALIGN_Right:
964 hr->fX += (w - wd);
965 break;
966
967 default:
968 break;
969 }
970 if (fMaxY < y) fMaxY = y;
971 if (fMaxX < wd + hr->fX) fMaxX = wd + hr->fX;
972 fBottom = y;
973 fHeadRoom = 0;
974 break;
975 }
976
977 case Html_ADDRESS:
978 case Html_EndADDRESS:
979 case Html_CENTER:
980 case Html_EndCENTER:
981 case Html_DIV:
982 case Html_EndDIV:
983 case Html_H1:
984 case Html_EndH1:
985 case Html_H2:
986 case Html_EndH2:
987 case Html_H3:
988 case Html_EndH3:
989 case Html_H4:
990 case Html_EndH4:
991 case Html_H5:
992 case Html_EndH5:
993 case Html_H6:
994 case Html_EndH6:
995 case Html_P:
996 case Html_EndP:
997 case Html_EndPRE:
998 case Html_EndFORM:
999 Paragraph(p);
1000 break;
1001
1002 case Html_TABLE:
1003 fPNext = TableLayout((TGHtmlTable *) p);
1004 break;
1005
1006 case Html_BR:
1007 z = p->MarkupArg("clear",0);
1008 if (z) {
1009 if (strcasecmp(z, "left") == 0) {
1011 } else if (strcasecmp(z, "right") == 0) {
1013 } else {
1015 }
1016 }
1017 if (p->fPNext && p->fPNext->fPNext && p->fPNext->fType == Html_Space &&
1018 p->fPNext->fPNext->fType == Html_BR) {
1019 Paragraph(p);
1020 }
1021 break;
1022
1023 // All of the following tags need to be handed to the GetLine() routine
1024 case Html_Text:
1025 case Html_Space:
1026 case Html_LI:
1027 case Html_INPUT:
1028 case Html_SELECT:
1029 case Html_TEXTAREA:
1030 case Html_APPLET:
1031 case Html_EMBED:
1032 fPNext = p;
1033 break;
1034
1035 default:
1036 break;
1037 }
1038
1039 return fPNext;
1040}
1041
1042////////////////////////////////////////////////////////////////////////////////
1043/// Return TRUE (non-zero) if we are currently wrapping text around
1044/// one or more images.
1045
1047{
1048 if (fLeftMargin && fLeftMargin->fBottom >= 0) return 1;
1049 if (fRightMargin && fRightMargin->fBottom >= 0) return 1;
1050 return 0;
1051}
1052
1053////////////////////////////////////////////////////////////////////////////////
1054/// Move past obstacles until a linewidth of reqWidth is obtained,
1055/// or until all obstacles are cleared.
1056///
1057/// reqWidth - Requested line width
1058/// pX, pY, pW - The margins. See ComputeMargins()
1059
1060void TGHtmlLayoutContext::WidenLine(int reqWidth, int *pX, int *pY, int *pW)
1061{
1062 ComputeMargins(pX, pY, pW);
1063 if (*pW < reqWidth && InWrapAround()) {
1065 ComputeMargins(pX, pY, pW);
1066 }
1067}
1068
1069
1070#ifdef TABLE_TRIM_BLANK
1071int HtmlLineWasBlank = 0;
1072#endif // TABLE_TRIM_BLANK
1073
1074////////////////////////////////////////////////////////////////////////////////
1075/// Do as much layout as possible on the block of text defined by
1076/// the HtmlLayoutContext.
1077
1079{
1080 TGHtmlElement *p, *pNext;
1081
1082 for (p = fPStart; p && p != fPEnd; p = pNext) {
1083 int lineWidth;
1084 int actualWidth;
1085 int y = 0;
1086 int lMargin;
1087 int max_x = 0;
1088
1089 // Do as much break markup as we can.
1090 while (p && p != fPEnd) {
1091 pNext = DoBreakMarkup(p);
1092 if (pNext == p) break;
1093 if (pNext) {
1094// TRACE(HtmlTrace_BreakMarkup,
1095// ("Processed token %s as break markup\n", HtmlTokenName(p)));
1096 fPStart = p;
1097 }
1098 p = pNext;
1099 }
1100
1101 if (p == 0 || p == fPEnd) break;
1102
1103#ifdef TABLE_TRIM_BLANK
1104 HtmlLineWasBlank = 0;
1105#endif // TABLE_TRIM_BLANK
1106
1107 // We might try several times to layout a single line...
1108 while (1) {
1109
1110 // Compute margins
1111 ComputeMargins(&lMargin, &y, &lineWidth);
1112
1113 // Layout a single line of text
1114 pNext = GetLine(p, fPEnd, lineWidth, fLeft-lMargin, &actualWidth);
1115// TRACE(HtmlTrace_GetLine,
1116// ("GetLine page=%d left=%d right=%d available=%d used=%d\n",
1117// fPageWidth, fLeft, fRight, lineWidth, actualWidth));
1118 FixAnchors(p, pNext, fBottom);
1119
1120 // Move down and repeat the layout if we exceeded the available
1121 // line length and it is possible to increase the line length by
1122 // moving past some obstacle.
1123
1124 if (actualWidth > lineWidth && InWrapAround()) {
1126 continue;
1127 }
1128
1129 // Lock the line into place and exit the loop
1130 y = FixLine(p, pNext, y, lineWidth, actualWidth, lMargin, &max_x);
1131 break;
1132 }
1133
1134#ifdef TABLE_TRIM_BLANK
1135
1136 // I noticed that a newline following break markup would result
1137 // in a blank line being drawn. So if an "empty" line was found
1138 // I subtract any whitespace caused by break markup.
1139
1140 if (actualWidth <= 0) HtmlLineWasBlank = 1;
1141
1142#endif // TABLE_TRIM_BLANK
1143
1144 // If a line was completed, advance to the next line
1145 if (pNext && actualWidth > 0 && y > fBottom) {
1146 PopIndent();
1147 fBottom = y;
1148 fPStart = pNext;
1149 }
1150 if (y > fMaxY) fMaxY = y;
1151 if (max_x > fMaxX) fMaxX = max_x;
1152 }
1153}
1154
1155////////////////////////////////////////////////////////////////////////////////
1156/// Adjust (push) ident.
1157
1159{
1161 if (fHtml->GetMarginWidth()) {
1164 }
1165}
1166
1167////////////////////////////////////////////////////////////////////////////////
1168/// Adjust (pop) ident.
1169
1171{
1172 if (fHeadRoom <= 0) return;
1173 fHeadRoom = 0;
1175}
1176
1177////////////////////////////////////////////////////////////////////////////////
1178/// Advance the layout as far as possible
1179
1181{
1182 int btm;
1183
1184 if (fPFirst == 0) return;
1185 Sizer();
1186 fLayoutContext.fHtml = this;
1187#if 0 // orig
1191#else
1195#endif
1199 if (fLayoutContext.fPStart) {
1200 TGHtmlElement *p;
1201
1204 btm = fLayoutContext.fBottom;
1207#if 0
1209#else
1211#endif
1213 fFlags |= HSCROLL | VSCROLL;
1214 if (fZGoto && (p = AttrElem("name", fZGoto+1))) {
1215 fVisible.fY = ((TGHtmlAnchor *)p)->fY;
1216 delete[] fZGoto;
1217 fZGoto = 0;
1218 }
1219 RedrawText(btm);
1220 }
1221}
static void indent(ostringstream &buf, int indent_level)
include TDocParser_001 C image html pict1_TDocParser_001 png width
#define CLEAR_First
#define CLEAR_Both
#define CLEAR_Right
#define CLEAR_Left
@ Html_EndBODY
@ Html_H3
@ Html_EndH4
@ Html_EndTH
@ Html_EndMENU
@ Html_BODY
@ Html_BLOCKQUOTE
@ Html_HR
@ Html_EndTABLE
@ Html_DL
@ Html_EndTEXTAREA
@ Html_TEXTAREA
@ Html_DT
@ Html_TD
@ Html_EMBED
@ Html_CENTER
@ Html_LI
@ Html_EndBLOCKQUOTE
@ Html_CAPTION
@ Html_EndLISTING
@ Html_EndADDRESS
@ Html_UL
@ Html_LISTING
@ Html_TABLE
@ Html_EndUL
@ Html_EndOL
@ Html_EndDIR
@ Html_H2
@ Html_APPLET
@ Html_TH
@ Html_EndFORM
@ Html_EndTD
@ Html_MENU
@ Html_WBR
@ Html_TR
@ Html_H6
@ Html_ADDRESS
@ Html_DIV
@ Html_Space
@ Html_EndH3
@ Html_SELECT
@ Html_H5
@ Html_Text
@ Html_H1
@ Html_EndDIV
@ Html_OL
@ Html_A
@ Html_P
@ Html_IMG
@ Html_EndDL
@ Html_EndCAPTION
@ Html_DIR
@ Html_H4
@ Html_EndH1
@ Html_EndH2
@ Html_EndH5
@ Html_DD
@ Html_EndDD
@ Html_BR
@ Html_EndHTML
@ Html_EndP
@ Html_EndH6
@ Html_EndPRE
@ Html_PRE
@ Html_INPUT
@ Html_Unknown
@ Html_EndCENTER
@ Html_EndTR
#define STY_Invisible
Definition TGHtml.h:239
#define ALIGN_Right
Definition TGHtml.h:209
#define IMAGE_ALIGN_Top
Definition TGHtml.h:562
#define HTML_RELIEF_SUNKEN
Definition TGHtml.h:51
#define STY_NoBreak
Definition TGHtml.h:236
#define HTML_RELIEF_RAISED
Definition TGHtml.h:52
#define HTML_NewLine
Definition TGHtml.h:275
#define IMAGE_ALIGN_Bottom
Definition TGHtml.h:560
#define STY_DT
Definition TGHtml.h:238
#define IMAGE_ALIGN_AbsMiddle
Definition TGHtml.h:564
#define ALIGN_Center
Definition TGHtml.h:210
#define HTML_INDENT
Definition TGHtml.h:753
#define IMAGE_ALIGN_Right
Definition TGHtml.h:567
#define IMAGE_ALIGN_Left
Definition TGHtml.h:566
#define STY_Preformatted
Definition TGHtml.h:233
#define VSCROLL
Definition TGHtml.h:1323
#define IMAGE_ALIGN_TextTop
Definition TGHtml.h:563
#define IMAGE_ALIGN_AbsBottom
Definition TGHtml.h:565
#define HSCROLL
Definition TGHtml.h:1322
#define ALIGN_None
Definition TGHtml.h:211
#define IMAGE_ALIGN_Middle
Definition TGHtml.h:561
void GetFontMetrics(FontMetrics_t *m) const
Get font metrics.
Definition TGFont.cxx:276
UInt_t GetWidth() const
Definition TGFrame.h:248
Html_u8_t fFlags
Definition TGHtml.h:265
Html_u8_t fType
Definition TGHtml.h:264
SHtmlStyle_t fStyle
Definition TGHtml.h:263
Html_16_t fCount
Definition TGHtml.h:266
virtual int IsMarkup() const
Definition TGHtml.h:253
TGHtmlElement * fPNext
Definition TGHtml.h:261
Html_32_t fY
Definition TGHtml.h:653
Html_u16_t fW
Definition TGHtml.h:655
Html_u16_t fX
Definition TGHtml.h:654
Html_u8_t fIs3D
Definition TGHtml.h:656
Html_u16_t fH
Definition TGHtml.h:655
Html_16_t fAscent
Definition TGHtml.h:546
Html_32_t fY
Definition TGHtml.h:549
Html_16_t fW
Definition TGHtml.h:545
Html_u8_t fTextAscent
Definition TGHtml.h:540
Html_16_t fDescent
Definition TGHtml.h:547
Html_16_t fH
Definition TGHtml.h:544
Html_u8_t fAlign
Definition TGHtml.h:539
Html_16_t fX
Definition TGHtml.h:548
Html_u8_t fTextDescent
Definition TGHtml.h:541
Html_u8_t fTextAscent
Definition TGHtml.h:600
Html_u16_t fW
Definition TGHtml.h:597
Html_u8_t fTextDescent
Definition TGHtml.h:601
Html_u16_t fH
Definition TGHtml.h:597
Html_u16_t fX
Definition TGHtml.h:596
Html_u8_t fPadLeft
Definition TGHtml.h:598
Html_32_t fY
Definition TGHtml.h:595
TGHtmlElement * fPStart
Definition TGHtml.h:795
int InWrapAround()
Return TRUE (non-zero) if we are currently wrapping text around one or more images.
TGHtmlElement * GetLine(TGHtmlElement *pStart, TGHtmlElement *pEnd, int width, int minX, int *actualWidth)
This routine gathers as many tokens as will fit on one line.
TGHtmlLayoutContext()
Html Layout Context constructor.
void ComputeMargins(int *pX, int *pY, int *pW)
Compute the current margins for layout.
TGHtmlElement * TableLayout(TGHtmlTable *p)
Do all layout for a single table.
void PopOneMargin(SHtmlMargin_t **ppMargin)
Pop one margin off of the given margin stack.
void PopMargin(SHtmlMargin_t **ppMargin, int tag)
Pop as many margins as necessary until the margin that was created with "tag" is popped off.
void LayoutBlock()
Do as much layout as possible on the block of text defined by the HtmlLayoutContext.
SHtmlMargin_t * fRightMargin
Definition TGHtml.h:805
void PushMargin(SHtmlMargin_t **ppMargin, int indent, int bottom, int tag)
Push a new margin onto the given margin stack.
void ClearMarginStack(SHtmlMargin_t **ppMargin)
Clear a margin stack to reclaim memory.
TGHtmlElement * DoBreakMarkup(TGHtmlElement *p)
Break markup is any kind of markup that might force a line-break.
void Paragraph(TGHtmlElement *p)
Increase the headroom to create a paragraph break at the current token.
int FixLine(TGHtmlElement *pStart, TGHtmlElement *pEnd, int bottom, int width, int actualWidth, int leftMargin, int *maxX)
This routine computes the X and Y coordinates for all elements of a line that has been gathered using...
void PopIndent()
Adjust (pop) ident.
void ClearObstacle(int mode)
Clear a wrap-around obstacle.
void WidenLine(int reqWidth, int *pX, int *pY, int *pW)
Move past obstacles until a linewidth of reqWidth is obtained, or until all obstacles are cleared.
void PopExpiredMargins(SHtmlMargin_t **ppMarginStack, int y)
Pop all expired margins from the stack.
void FixAnchors(TGHtmlElement *p, TGHtmlElement *pEnd, int y)
Set the y coordinate for every anchor in the given list.
TGHtmlElement * fPEnd
Definition TGHtml.h:796
SHtmlMargin_t * fLeftMargin
Definition TGHtml.h:804
void Reset()
Reset the layout context.
void PushIndent()
Adjust (push) ident.
Html_u8_t fDescent
Definition TGHtml.h:425
Html_32_t fY
Definition TGHtml.h:428
Html_16_t fX
Definition TGHtml.h:427
virtual const char * MarkupArg(const char *tag, const char *zDefault)
Lookup an argument in the given markup with the name given.
TGHtmlElement * fPOther
Definition TGHtml.h:410
Html_u8_t fAscent
Definition TGHtml.h:309
Html_16_t fW
Definition TGHtml.h:308
char * fZGoto
Definition TGHtml.h:1272
TGHtmlElement * fPFirst
Definition TGHtml.h:1128
virtual TGFont * GetFont(int iFont)
The rendering and layout routines should call this routine in order to get a font structure.
Definition TGHtml.cxx:1408
void LayoutDoc()
Advance the layout as far as possible.
int NextMarkupType(TGHtmlElement *p)
Return the next markup type [TGHtmlElement::NextMarkupType].
int fFlags
Definition TGHtml.h:1269
void RedrawText(int y)
Call this routine to cause all of the rendered HTML at the virtual canvas coordinate of Y and beyond ...
Definition TGHtml.cxx:877
int fMaxY
Definition TGHtml.h:1262
int GetMarginHeight()
Definition TGHtml.h:964
int fMaxX
Definition TGHtml.h:1262
void Sizer()
Compute the size of all elements in the widget.
TGHtmlElement * AttrElem(const char *name, char *value)
Returns html element matching attribute name and value.
Definition TGHtml.cxx:1850
int GetRulePadding() const
Definition TGHtml.h:901
TGHtmlElement * fNextPlaced
Definition TGHtml.h:1133
TGHtmlLayoutContext fLayoutContext
Definition TGHtml.h:1207
int GetRuleRelief() const
Definition TGHtml.h:900
int GetMarginWidth()
Definition TGHtml.h:963
TGLongPosition fVisible
Definition TGView.h:51
TGViewFrame * fCanvas
Definition TGView.h:61
UInt_t fYMargin
Definition TGView.h:60
Double_t fY
Y position of text (left,center,etc..)
Definition TText.h:26
Double_t fX
X position of text (left,center,etc..)
Definition TText.h:25
TText * text
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
Int_t fAscent
Definition TGFont.h:62
Int_t fDescent
Definition TGFont.h:63
SHtmlMargin_t * fPNext
Definition TGHtml.h:746
signed int fSubscript
Definition TGHtml.h:146
unsigned int fAlign
Definition TGHtml.h:147
unsigned int fFont
Definition TGHtml.h:144
unsigned int fFlags
Definition TGHtml.h:150