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
71/// `<IMG 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>`)
150/// and 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: {
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 maxAscent = maxTextAscent = 0;
470 for (p = p_start; p && p != p_end; p = p->fPNext) {
471 int ss;
472 if (p->fStyle.fAlign == ALIGN_Center) {
473 dx = lMargin + (width - actualWidth) / 2;
474 } else if (p->fStyle.fAlign == ALIGN_Right) {
475 dx = lMargin + (width - actualWidth);
476 } else {
477 dx = lMargin;
478 }
479 if (dx < 0) dx = 0;
480 if (p->fStyle.fFlags & STY_Invisible) continue;
481 switch (p->fType) {
482 case Html_Text: {
484 text->fX += dx;
485 max = text->fX + text->fW;
486 ss = p->fStyle.fSubscript;
487 if (ss > 0) {
488 int ascent2 = text->fAscent;
489 int delta = (ascent2 + text->fDescent) * ss / 2;
490 ascent2 += delta;
491 text->fY = -delta;
492 if (ascent2 > maxAscent) maxAscent = ascent2;
493 if (ascent2 > maxTextAscent) maxTextAscent = ascent2;
494 } else if (ss < 0) {
495 int descent2 = text->fDescent;
496 int delta = (descent2 + text->fAscent) * (-ss) / 2;
497 text->fY = delta;
498 } else {
499 text->fY = 0;
500 if (text->fAscent > maxAscent) maxAscent = text->fAscent;
501 if (text->fAscent > maxTextAscent) maxTextAscent = text->fAscent;
502 }
503 break;
504 }
505
506 case Html_Space: {
508 if (space->fAscent > maxAscent) maxAscent = space->fAscent;
509 break;
510 }
511
512 case Html_LI: {
513 TGHtmlLi *li = (TGHtmlLi *) p;
514 li->fX += dx;
515 if (li->fX > max) max = li->fX;
516 break;
517 }
518
519 case Html_IMG: {
521 image->fX += dx;
522 max = image->fX + image->fW;
523 switch (image->fAlign) {
525 image->fDescent = image->fH / 2;
526 image->fAscent = image->fH - image->fDescent;
527 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
528 break;
529
531 dy2center = (image->fTextDescent - image->fTextAscent) / 2;
532 image->fDescent = image->fH / 2 + dy2center;
533 image->fAscent = image->fH - image->fDescent;
534 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
535 break;
536
538 image->fDescent = 0;
539 image->fAscent = image->fH;
540 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
541 break;
542
544 image->fDescent = image->fTextDescent;
545 image->fAscent = image->fH - image->fDescent;
546 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
547 break;
548
549 default:
550 break;
551 }
552 break;
553 }
554
555 case Html_TABLE:
556 break;
557
558 case Html_TEXTAREA:
559 case Html_INPUT:
560 case Html_SELECT:
561 case Html_EMBED:
562 case Html_APPLET: {
564 input->fX += dx;
565 max = input->fX + input->fW;
566 dy2center = (input->fTextDescent - input->fTextAscent) / 2;
567 input->fY = dy2center - input->fH / 2;
568 ascent = -input->fY;
569 if (ascent > maxAscent) maxAscent = ascent;
570 break;
571 }
572
573 default:
574 // Shouldn't happen
575 break;
576 }
577 }
578
579 *max_x = max;
580 y = maxAscent + mbottom;
581 maxDescent = 0;
582
583 for (p = p_start; p && p != p_end; p = p->fPNext) {
584 if (p->fStyle.fFlags & STY_Invisible) continue;
585 switch (p->fType) {
586 case Html_Text: {
588 text->fY += y;
589 if (text->fDescent > maxDescent) maxDescent = text->fDescent;
590 break;
591 }
592
593 case Html_LI: {
594 TGHtmlLi *li = (TGHtmlLi *) p;
595 li->fY = y;
596 if (li->fDescent > maxDescent) maxDescent = li->fDescent;
597 break;
598 }
599
600 case Html_IMG: {
602 image->fY = y;
603 switch (image->fAlign) {
604 case IMAGE_ALIGN_Top:
605 image->fAscent = maxAscent;
606 image->fDescent = image->fH - maxAscent;
607 break;
608
610 image->fAscent = maxTextAscent;
611 image->fDescent = image->fH - maxTextAscent;
612 break;
613
614 default:
615 break;
616 }
617 if (image->fDescent > maxDescent) maxDescent = image->fDescent;
618 break;
619 }
620
621 case Html_TABLE:
622 break;
623
624 case Html_INPUT:
625 case Html_SELECT:
626 case Html_TEXTAREA:
627 case Html_APPLET:
628 case Html_EMBED: {
630 descent = input->fY + input->fH;
631 input->fY += y;
632 if (descent > maxDescent) maxDescent = descent;
633 break;
634 }
635
636 default:
637 /* Shouldn't happen */
638 break;
639 }
640 }
641
642// TRACE(HtmlTrace_FixLine,
643// ("Setting baseline to %d. mbottom=%d ascent=%d descent=%d dx=%d\n",
644// y, mbottom, maxAscent, maxDescent, dx));
645
646 } else {
647 maxDescent = 0;
648 y = mbottom;
649 }
650
651 return y + maxDescent;
652}
653
654////////////////////////////////////////////////////////////////////////////////
655/// Increase the headroom to create a paragraph break at the current token
656
658{
659 int headroom;
660
661 if (p == 0) return;
662
663 if (p->fType == Html_Text) {
665 headroom = text->fAscent + text->fDescent;
666 } else if (p->fPNext && p->fPNext->fType == Html_Text) {
668 headroom = text->fAscent + text->fDescent;
669 } else {
670 //// headroom = 10;
671 FontMetrics_t fontMetrics;
672 TGFont *font;
673 font = fHtml->GetFont(p->fStyle.fFont);
674 if (font == 0) return;
675 font->GetFontMetrics(&fontMetrics);
676 headroom = fontMetrics.fDescent + fontMetrics.fAscent;
677 }
678 if (fHeadRoom < headroom && fBottom > fTop) fHeadRoom = headroom;
679}
680
681////////////////////////////////////////////////////////////////////////////////
682/// Compute the current margins for layout. Three values are returned:
683///
684/// *pY The top edge of the area in which we can put ink. This
685/// takes into account any requested headroom.
686///
687/// *pX The left edge of the inkable area. The takes into account
688/// any margin requests active at vertical position specified
689/// in pLC->bottom.
690///
691/// *pW The width of the inkable area. This takes into account
692/// an margin requests that are active at the vertical position
693/// pLC->bottom.
694///
695
696void TGHtmlLayoutContext::ComputeMargins(int *pX, int *pY, int *pW)
697{
698 int x, y, w;
699
700 y = fBottom + fHeadRoom;
703 w = fPageWidth - fRight;
704 if (fLeftMargin) {
706 } else {
707 x = fLeft;
708 }
709 w -= x;
711
712 *pX = x;
713 *pY = y;
714 *pW = w;
715}
716
717#define CLEAR_Left 0
718#define CLEAR_Right 1
719#define CLEAR_Both 2
720#define CLEAR_First 3
721////////////////////////////////////////////////////////////////////////////////
722/// Clear a wrap-around obstacle. The second option determines the
723/// precise behavior.
724///
725/// CLEAR_Left Clear all obstacles on the left.
726///
727/// CLEAR_Right Clear all obstacles on the right.
728///
729/// CLEAR_Both Clear all obstacles on both sides.
730///
731/// CLEAR_First Clear only the first obstacle on either side.
732
734{
735 int newBottom = fBottom;
736
739
740 switch (mode) {
741 case CLEAR_Both:
744 break;
745
746 case CLEAR_Left:
747 while (fLeftMargin && fLeftMargin->fBottom >= 0) {
748 if (newBottom < fLeftMargin->fBottom) {
749 newBottom = fLeftMargin->fBottom;
750 }
752 }
753 if (newBottom > fBottom + fHeadRoom) {
754 fHeadRoom = 0;
755 } else {
756 fHeadRoom = newBottom - fBottom;
757 }
758 fBottom = newBottom;
760 break;
761
762 case CLEAR_Right:
763 while (fRightMargin && fRightMargin->fBottom >= 0) {
764 if (newBottom < fRightMargin->fBottom) {
765 newBottom = fRightMargin->fBottom;
766 }
768 }
769 if (newBottom > fBottom + fHeadRoom) {
770 fHeadRoom = 0;
771 } else {
772 fHeadRoom = newBottom - fBottom;
773 }
774 fBottom = newBottom;
776 break;
777
778 case CLEAR_First:
779 if (fLeftMargin && fLeftMargin->fBottom >= 0) {
780 if (fRightMargin &&
782 if (newBottom < fRightMargin->fBottom) {
783 newBottom = fRightMargin->fBottom;
784 }
786 } else {
787 if (newBottom < fLeftMargin->fBottom) {
788 newBottom = fLeftMargin->fBottom;
789 }
791 }
792 } else if (fRightMargin && fRightMargin->fBottom >= 0) {
793 newBottom = fRightMargin->fBottom;
795 }
796 if (newBottom > fBottom + fHeadRoom) {
797 fHeadRoom = 0;
798 } else {
799 fHeadRoom = newBottom - fBottom;
800 }
801 fBottom = newBottom;
802 break;
803
804 default:
805 break;
806 }
807}
808
809////////////////////////////////////////////////////////////////////////////////
810/// Return the next markup type [TGHtmlElement::NextMarkupType]
811
813{
814 while ((p = p->fPNext)) {
815 if (p->IsMarkup()) return p->fType;
816 }
817 return Html_Unknown;
818}
819
820////////////////////////////////////////////////////////////////////////////////
821/// Break markup is any kind of markup that might force a line-break. This
822/// routine handles a single element of break markup and returns a pointer
823/// to the first element past that markup. If p doesn't point to break
824/// markup, then p is returned. If p is an incomplete table (a `<TABLE>`
825/// that lacks a `</TABLE>`), then `NULL` is returned.
826
828{
829 TGHtmlElement *fPNext = p->fPNext;
830 const char *z;
831 int x, y, w;
832
833 switch (p->fType) {
834 case Html_A:
835 ((TGHtmlAnchor *)p)->fY = fBottom;
836 break;
837
838 case Html_BLOCKQUOTE:
841 Paragraph(p);
842 break;
843
847 Paragraph(p);
848 break;
849
850 case Html_IMG: {
852 switch (image->fAlign) {
853 case IMAGE_ALIGN_Left:
854 ComputeMargins(&x, &y, &w);
855 image->fX = x;
856 image->fY = y;
857 image->fAscent = 0;
858 image->fDescent = image->fH;
859 PushMargin(&fLeftMargin, image->fW + 2, y + image->fH, 0);
860 if (fMaxY < y + image->fH) fMaxY = y + image->fH;
861 if (fMaxX < x + image->fW) fMaxX = x + image->fW;
862 break;
863
865 ComputeMargins(&x, &y, &w);
866 image->fX = x + w - image->fW;
867 image->fY = y;
868 image->fAscent = 0;
869 image->fDescent = image->fH;
870 PushMargin(&fRightMargin, image->fW + 2, y + image->fH, 0);
871 if (fMaxY < y + image->fH) fMaxY = y + image->fH;
872 if (fMaxX < x + image->fW) fMaxX = x + image->fW;
873 break;
874
875 default:
876 fPNext = p;
877 break;
878 }
879 break;
880 }
881
882 case Html_PRE:
883 // Skip space tokens thru the next newline.
884 while (fPNext->fType == Html_Space) {
885 TGHtmlElement *pThis = fPNext;
886 fPNext = fPNext->fPNext;
887 if (pThis->fFlags & HTML_NewLine) break;
888 }
889 Paragraph(p);
890 break;
891
892 case Html_UL:
893 case Html_MENU:
894 case Html_DIR:
895 case Html_OL:
896 if (((TGHtmlListStart *)p)->fCompact == 0) Paragraph(p);
897 PushMargin(&fLeftMargin, HTML_INDENT, -1, p->fType + 1);
898 break;
899
900 case Html_EndOL:
901 case Html_EndUL:
902 case Html_EndMENU:
903 case Html_EndDIR: {
904 TGHtmlRef *ref = (TGHtmlRef *) p;
905 if (ref->fPOther) {
906 PopMargin(&fLeftMargin, p->fType);
907 if (!((TGHtmlListStart *)ref->fPOther)->fCompact) Paragraph(p);
908 }
909 break;
910 }
911
912 case Html_DL:
913 Paragraph(p);
915 break;
916
917 case Html_EndDL:
919 Paragraph(p);
920 break;
921
922 case Html_HR: {
923 int zl, wd;
924 TGHtmlHr *hr = (TGHtmlHr *) p;
925 hr->fIs3D = (p->MarkupArg("noshade", 0) == 0);
926 z = p->MarkupArg("size", 0);
927 if (z) {
928 int hrsz = atoi(z);
929 hr->fH = (hrsz < 0) ? 2 : hrsz;
930 } else {
931 hr->fH = 0;
932 }
933 if (hr->fH < 1) {
934 int relief = fHtml->GetRuleRelief();
935 if (hr->fIs3D &&
936 (relief == HTML_RELIEF_SUNKEN || relief == HTML_RELIEF_RAISED)) {
937 hr->fH = 3;
938 } else {
939 hr->fH = 2;
940 }
941 }
942 ComputeMargins(&x, &y, &w);
943 hr->fY = y + fHtml->GetRulePadding();
944 y += hr->fH + fHtml->GetRulePadding() * 2 + 1;
945 hr->fX = x;
946 z = p->MarkupArg("width", "100%");
947 zl = z ? strlen(z) : 0;
948 if (zl > 0 && z[zl-1] == '%') {
949 wd = (atoi(z) * w) / 100;
950 } else {
951 wd = z ? atoi(z) : w;
952 }
953 if (wd > w) wd = w;
954 hr->fW = wd;
955 switch (p->fStyle.fAlign) {
956 case ALIGN_Center:
957 case ALIGN_None:
958 hr->fX += (w - wd) / 2;
959 break;
960
961 case ALIGN_Right:
962 hr->fX += (w - wd);
963 break;
964
965 default:
966 break;
967 }
968 if (fMaxY < y) fMaxY = y;
969 if (fMaxX < wd + hr->fX) fMaxX = wd + hr->fX;
970 fBottom = y;
971 fHeadRoom = 0;
972 break;
973 }
974
975 case Html_ADDRESS:
976 case Html_EndADDRESS:
977 case Html_CENTER:
978 case Html_EndCENTER:
979 case Html_DIV:
980 case Html_EndDIV:
981 case Html_H1:
982 case Html_EndH1:
983 case Html_H2:
984 case Html_EndH2:
985 case Html_H3:
986 case Html_EndH3:
987 case Html_H4:
988 case Html_EndH4:
989 case Html_H5:
990 case Html_EndH5:
991 case Html_H6:
992 case Html_EndH6:
993 case Html_P:
994 case Html_EndP:
995 case Html_EndPRE:
996 case Html_EndFORM:
997 Paragraph(p);
998 break;
999
1000 case Html_TABLE:
1001 fPNext = TableLayout((TGHtmlTable *) p);
1002 break;
1003
1004 case Html_BR:
1005 z = p->MarkupArg("clear",0);
1006 if (z) {
1007 if (strcasecmp(z, "left") == 0) {
1009 } else if (strcasecmp(z, "right") == 0) {
1011 } else {
1013 }
1014 }
1015 if (p->fPNext && p->fPNext->fPNext && p->fPNext->fType == Html_Space &&
1016 p->fPNext->fPNext->fType == Html_BR) {
1017 Paragraph(p);
1018 }
1019 break;
1020
1021 // All of the following tags need to be handed to the GetLine() routine
1022 case Html_Text:
1023 case Html_Space:
1024 case Html_LI:
1025 case Html_INPUT:
1026 case Html_SELECT:
1027 case Html_TEXTAREA:
1028 case Html_APPLET:
1029 case Html_EMBED:
1030 fPNext = p;
1031 break;
1032
1033 default:
1034 break;
1035 }
1036
1037 return fPNext;
1038}
1039
1040////////////////////////////////////////////////////////////////////////////////
1041/// Return TRUE (non-zero) if we are currently wrapping text around
1042/// one or more images.
1043
1045{
1046 if (fLeftMargin && fLeftMargin->fBottom >= 0) return 1;
1047 if (fRightMargin && fRightMargin->fBottom >= 0) return 1;
1048 return 0;
1049}
1050
1051////////////////////////////////////////////////////////////////////////////////
1052/// Move past obstacles until a linewidth of reqWidth is obtained,
1053/// or until all obstacles are cleared.
1054///
1055/// reqWidth - Requested line width
1056/// pX, pY, pW - The margins. See ComputeMargins()
1057
1058void TGHtmlLayoutContext::WidenLine(int reqWidth, int *pX, int *pY, int *pW)
1059{
1060 ComputeMargins(pX, pY, pW);
1061 if (*pW < reqWidth && InWrapAround()) {
1063 ComputeMargins(pX, pY, pW);
1064 }
1065}
1066
1067
1068#ifdef TABLE_TRIM_BLANK
1069int HtmlLineWasBlank = 0;
1070#endif // TABLE_TRIM_BLANK
1071
1072////////////////////////////////////////////////////////////////////////////////
1073/// Do as much layout as possible on the block of text defined by
1074/// the HtmlLayoutContext.
1075
1077{
1078 TGHtmlElement *p, *pNext;
1079
1080 for (p = fPStart; p && p != fPEnd; p = pNext) {
1081 int lineWidth;
1082 int actualWidth;
1083 int y = 0;
1084 int lMargin;
1085 int max_x = 0;
1086
1087 // Do as much break markup as we can.
1088 while (p && p != fPEnd) {
1089 pNext = DoBreakMarkup(p);
1090 if (pNext == p) break;
1091 if (pNext) {
1092// TRACE(HtmlTrace_BreakMarkup,
1093// ("Processed token %s as break markup\n", HtmlTokenName(p)));
1094 fPStart = p;
1095 }
1096 p = pNext;
1097 }
1098
1099 if (p == 0 || p == fPEnd) break;
1100
1101#ifdef TABLE_TRIM_BLANK
1102 HtmlLineWasBlank = 0;
1103#endif // TABLE_TRIM_BLANK
1104
1105 // We might try several times to layout a single line...
1106 while (1) {
1107
1108 // Compute margins
1109 ComputeMargins(&lMargin, &y, &lineWidth);
1110
1111 // Layout a single line of text
1112 pNext = GetLine(p, fPEnd, lineWidth, fLeft-lMargin, &actualWidth);
1113// TRACE(HtmlTrace_GetLine,
1114// ("GetLine page=%d left=%d right=%d available=%d used=%d\n",
1115// fPageWidth, fLeft, fRight, lineWidth, actualWidth));
1116 FixAnchors(p, pNext, fBottom);
1117
1118 // Move down and repeat the layout if we exceeded the available
1119 // line length and it is possible to increase the line length by
1120 // moving past some obstacle.
1121
1122 if (actualWidth > lineWidth && InWrapAround()) {
1124 continue;
1125 }
1126
1127 // Lock the line into place and exit the loop
1128 y = FixLine(p, pNext, y, lineWidth, actualWidth, lMargin, &max_x);
1129 break;
1130 }
1131
1132#ifdef TABLE_TRIM_BLANK
1133
1134 // I noticed that a newline following break markup would result
1135 // in a blank line being drawn. So if an "empty" line was found
1136 // I subtract any whitespace caused by break markup.
1137
1138 if (actualWidth <= 0) HtmlLineWasBlank = 1;
1139
1140#endif // TABLE_TRIM_BLANK
1141
1142 // If a line was completed, advance to the next line
1143 if (pNext && actualWidth > 0 && y > fBottom) {
1144 PopIndent();
1145 fBottom = y;
1146 fPStart = pNext;
1147 }
1148 if (y > fMaxY) fMaxY = y;
1149 if (max_x > fMaxX) fMaxX = max_x;
1150 }
1151}
1152
1153////////////////////////////////////////////////////////////////////////////////
1154/// Adjust (push) ident.
1155
1157{
1159 if (fHtml->GetMarginWidth()) {
1162 }
1163}
1164
1165////////////////////////////////////////////////////////////////////////////////
1166/// Adjust (pop) ident.
1167
1169{
1170 if (fHeadRoom <= 0) return;
1171 fHeadRoom = 0;
1173}
1174
1175////////////////////////////////////////////////////////////////////////////////
1176/// Advance the layout as far as possible
1177
1179{
1180 int btm;
1181
1182 if (fPFirst == 0) return;
1183 Sizer();
1184 fLayoutContext.fHtml = this;
1185#if 0 // orig
1189#else
1193#endif
1197 if (fLayoutContext.fPStart) {
1199
1202 btm = fLayoutContext.fBottom;
1205#if 0
1207#else
1209#endif
1211 fFlags |= HSCROLL | VSCROLL;
1212 if (fZGoto && (p = AttrElem("name", fZGoto+1))) {
1213 fVisible.fY = ((TGHtmlAnchor *)p)->fY;
1214 delete[] fZGoto;
1215 fZGoto = 0;
1216 }
1217 RedrawText(btm);
1218 }
1219}
static void indent(ostringstream &buf, int indent_level)
#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:240
#define ALIGN_Right
Definition TGHtml.h:210
#define IMAGE_ALIGN_Top
Definition TGHtml.h:563
#define HTML_RELIEF_SUNKEN
Definition TGHtml.h:52
#define STY_NoBreak
Definition TGHtml.h:237
#define HTML_RELIEF_RAISED
Definition TGHtml.h:53
#define HTML_NewLine
Definition TGHtml.h:276
#define IMAGE_ALIGN_Bottom
Definition TGHtml.h:561
#define STY_DT
Definition TGHtml.h:239
#define IMAGE_ALIGN_AbsMiddle
Definition TGHtml.h:565
#define ALIGN_Center
Definition TGHtml.h:211
#define HTML_INDENT
Definition TGHtml.h:754
#define IMAGE_ALIGN_Right
Definition TGHtml.h:568
#define IMAGE_ALIGN_Left
Definition TGHtml.h:567
#define STY_Preformatted
Definition TGHtml.h:234
#define VSCROLL
Definition TGHtml.h:1332
#define IMAGE_ALIGN_TextTop
Definition TGHtml.h:564
#define IMAGE_ALIGN_AbsBottom
Definition TGHtml.h:566
#define HSCROLL
Definition TGHtml.h:1331
#define ALIGN_None
Definition TGHtml.h:212
#define IMAGE_ALIGN_Middle
Definition TGHtml.h:562
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t width
Option_t Option_t TPoint TPoint const char text
Encapsulate fonts used in the GUI system.
Definition TGFont.h:140
void GetFontMetrics(FontMetrics_t *m) const
Get font metrics.
Definition TGFont.cxx:286
UInt_t GetWidth() const
Definition TGFrame.h:224
Html_u8_t fFlags
Definition TGHtml.h:266
Html_u8_t fType
Definition TGHtml.h:265
TGHtmlElement * fPNext
Definition TGHtml.h:262
Html_32_t fY
Definition TGHtml.h:654
Html_u16_t fW
Definition TGHtml.h:656
Html_u16_t fX
Definition TGHtml.h:655
Html_u8_t fIs3D
Definition TGHtml.h:657
Html_u16_t fH
Definition TGHtml.h:656
Html_16_t fAscent
Definition TGHtml.h:547
Html_32_t fY
Definition TGHtml.h:550
Html_16_t fW
Definition TGHtml.h:546
Html_u8_t fTextAscent
Definition TGHtml.h:541
Html_16_t fDescent
Definition TGHtml.h:548
Html_16_t fH
Definition TGHtml.h:545
Html_u8_t fAlign
Definition TGHtml.h:540
Html_16_t fX
Definition TGHtml.h:549
Html_u8_t fTextDescent
Definition TGHtml.h:542
TGHtmlElement * fPStart
Definition TGHtml.h:796
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:806
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:797
SHtmlMargin_t * fLeftMargin
Definition TGHtml.h:805
void Reset()
Reset the layout context.
void PushIndent()
Adjust (push) ident.
Html_u8_t fDescent
Definition TGHtml.h:426
Html_32_t fY
Definition TGHtml.h:429
Html_16_t fX
Definition TGHtml.h:428
TGHtmlElement * fPOther
Definition TGHtml.h:411
Html_u8_t fAscent
Definition TGHtml.h:310
Html_16_t fW
Definition TGHtml.h:309
char * fZGoto
Definition TGHtml.h:1281
TGHtmlElement * fPFirst
Definition TGHtml.h:1136
virtual TGFont * GetFont(int iFont)
The rendering and layout routines should call this routine in order to get a font structure.
Definition TGHtml.cxx:1465
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:1278
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:887
int fMaxY
Definition TGHtml.h:1271
int GetMarginHeight()
Definition TGHtml.h:968
int fMaxX
Definition TGHtml.h:1271
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:1907
int GetRulePadding() const
Definition TGHtml.h:902
TGHtmlElement * fNextPlaced
Definition TGHtml.h:1141
TGHtmlLayoutContext fLayoutContext
Definition TGHtml.h:1216
int GetRuleRelief() const
Definition TGHtml.h:901
int GetMarginWidth()
Definition TGHtml.h:967
Long_t fY
y position
Definition TGDimension.h:57
TGLongPosition fVisible
position of visible region
Definition TGView.h:32
TGViewFrame * fCanvas
frame containing the text
Definition TGView.h:42
UInt_t fYMargin
y margin
Definition TGView.h:41
SCoord_t fY
Definition TPoint.h:36
SCoord_t fX
Definition TPoint.h:35
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
Int_t fAscent
Definition TGFont.h:53
Int_t fDescent
Definition TGFont.h:54
SHtmlMargin_t * fPNext
Definition TGHtml.h:747