38 TGHtmlLayoutContext::TGHtmlLayoutContext()
56 void TGHtmlLayoutContext::Reset()
61 ClearMarginStack(&fLeftMargin);
62 ClearMarginStack(&fRightMargin);
81 void TGHtmlLayoutContext::PushMargin(SHtmlMargin_t **ppMargin,
82 int indent,
int mbottom,
int tag)
84 SHtmlMargin_t *pNew =
new SHtmlMargin_t;
85 pNew->fPNext = *ppMargin;
87 pNew->fIndent = indent + pNew->fPNext->fIndent;
89 pNew->fIndent = indent;
91 pNew->fBottom = mbottom;
99 void TGHtmlLayoutContext::PopOneMargin(SHtmlMargin_t **ppMargin)
102 SHtmlMargin_t *pOld = *ppMargin;
103 *ppMargin = pOld->fPNext;
119 void TGHtmlLayoutContext::PopMargin(SHtmlMargin_t **ppMargin,
int tag)
125 for (pM = *ppMargin; pM && pM->fTag != tag; pM = pM->fPNext) {}
130 while ((pM = *ppMargin) != 0) {
131 if (pM->fBottom > bot) bot = pM->fBottom;
133 PopOneMargin(ppMargin);
134 if (oldTag == tag)
break;
137 fHeadRoom += bot - fBottom;
152 void TGHtmlLayoutContext::PopExpiredMargins(SHtmlMargin_t **ppMarginStack,
int y)
154 while (*ppMarginStack && (**ppMarginStack).fBottom >= 0 &&
155 (**ppMarginStack).fBottom <= y) {
156 PopOneMargin(ppMarginStack);
165 void TGHtmlLayoutContext::ClearMarginStack(SHtmlMargin_t **ppMargin)
167 while (*ppMargin) PopOneMargin(ppMargin);
203 TGHtmlElement *TGHtmlLayoutContext::GetLine(TGHtmlElement *p_start,
204 TGHtmlElement *p_end,
int width,
int minX,
int *actualWidth)
209 TGHtmlElement *lastBreak = 0;
215 while (p && p != p_end && (p->fStyle.fFlags & STY_Invisible) != 0) {
218 if (p && p->fStyle.fFlags & STY_DT) {
219 origin = -HTML_INDENT;
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;
235 while (p && (p->fType == Html_Space || p->fType == Html_P)) {
240 for (; p && p != p_end; p = p ? p->fPNext : 0) {
241 if (p->fStyle.fFlags & STY_Invisible)
continue;
244 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
245 text->fX = x + spaceWanted;
246 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
247 if (lastBreak && x + spaceWanted + text->fW > width)
252 x += text->fW + spaceWanted;
259 TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
260 if (p->fStyle.fFlags & STY_Preformatted) {
261 if (p->fFlags & HTML_NewLine) {
262 *actualWidth = (x <= 0) ? 1 : x;
265 x += space->fW * p->fCount;
268 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
269 lastBreak = p->fPNext;
270 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
273 if (spaceWanted < w && x > origin) spaceWanted = w;
279 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
280 switch (image->fAlign) {
281 case IMAGE_ALIGN_Left:
282 case IMAGE_ALIGN_Right:
283 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
288 image->fX = x + spaceWanted;
289 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
290 if (lastBreak && x + spaceWanted + image->fW > width) {
296 x += image->fW + spaceWanted;
297 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
298 lastBreak = p->fPNext;
299 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
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) {
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;
330 case Html_EndTEXTAREA: {
331 TGHtmlRef *ref = (TGHtmlRef *) p;
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;
352 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
353 if (x + spaceWanted >= width) {
356 lastBreak = p->fPNext;
361 case Html_EndADDRESS:
362 case Html_BLOCKQUOTE:
363 case Html_EndBLOCKQUOTE:
368 case Html_EndCAPTION:
393 case Html_EndLISTING:
413 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
420 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
428 void TGHtmlLayoutContext::FixAnchors(TGHtmlElement *p, TGHtmlElement *p_end,
int y)
430 while (p && p != p_end) {
431 if (p->fType == Html_A) ((TGHtmlAnchor *)p)->fY = y;
453 int TGHtmlLayoutContext::FixLine(TGHtmlElement *p_start,
454 TGHtmlElement *p_end,
int mbottom,
int width,
455 int actualWidth,
int lMargin,
int *max_x)
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) {
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);
481 if (p->fStyle.fFlags & STY_Invisible)
continue;
484 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
486 max = text->fX + text->fW;
487 ss = p->fStyle.fSubscript;
489 int ascent2 = text->fAscent;
490 int delta = (ascent2 + text->fDescent) * ss / 2;
493 if (ascent2 > maxAscent) maxAscent = ascent2;
494 if (ascent2 > maxTextAscent) maxTextAscent = ascent2;
496 int descent2 = text->fDescent;
497 int delta = (descent2 + text->fAscent) * (-ss) / 2;
502 if (text->fAscent > maxAscent) maxAscent = text->fAscent;
503 if (text->fAscent > maxTextAscent) maxTextAscent = text->fAscent;
509 TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
510 if (space->fAscent > maxAscent) maxAscent = space->fAscent;
515 TGHtmlLi *li = (TGHtmlLi *) p;
517 if (li->fX > max) max = li->fX;
522 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
524 max = image->fX + image->fW;
525 switch (image->fAlign) {
526 case IMAGE_ALIGN_Middle:
527 image->fDescent = image->fH / 2;
528 image->fAscent = image->fH - image->fDescent;
529 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
532 case IMAGE_ALIGN_AbsMiddle:
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;
539 case IMAGE_ALIGN_Bottom:
541 image->fAscent = image->fH;
542 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
545 case IMAGE_ALIGN_AbsBottom:
546 image->fDescent = image->fTextDescent;
547 image->fAscent = image->fH - image->fDescent;
548 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
565 TGHtmlInput *input = (TGHtmlInput *) p;
567 max = input->fX + input->fW;
568 dy2center = (input->fTextDescent - input->fTextAscent) / 2;
569 input->fY = dy2center - input->fH / 2;
571 if (ascent > maxAscent) maxAscent = ascent;
582 y = maxAscent + mbottom;
585 for (p = p_start; p && p != p_end; p = p->fPNext) {
586 if (p->fStyle.fFlags & STY_Invisible)
continue;
589 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
591 if (text->fDescent > maxDescent) maxDescent = text->fDescent;
596 TGHtmlLi *li = (TGHtmlLi *) p;
598 if (li->fDescent > maxDescent) maxDescent = li->fDescent;
603 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
605 switch (image->fAlign) {
606 case IMAGE_ALIGN_Top:
607 image->fAscent = maxAscent;
608 image->fDescent = image->fH - maxAscent;
611 case IMAGE_ALIGN_TextTop:
612 image->fAscent = maxTextAscent;
613 image->fDescent = image->fH - maxTextAscent;
619 if (image->fDescent > maxDescent) maxDescent = image->fDescent;
631 TGHtmlInput *input = (TGHtmlInput *) p;
632 descent = input->fY + input->fH;
634 if (descent > maxDescent) maxDescent = descent;
653 return y + maxDescent;
659 void TGHtmlLayoutContext::Paragraph(TGHtmlElement *p)
665 if (p->fType == Html_Text) {
666 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
667 headroom = text->fAscent + text->fDescent;
668 }
else if (p->fPNext && p->fPNext->fType == Html_Text) {
669 TGHtmlTextElement *text = (TGHtmlTextElement *) p->fPNext;
670 headroom = text->fAscent + text->fDescent;
673 FontMetrics_t fontMetrics;
675 font = fHtml->GetFont(p->fStyle.fFont);
676 if (font == 0)
return;
677 font->GetFontMetrics(&fontMetrics);
678 headroom = fontMetrics.fDescent + fontMetrics.fAscent;
680 if (fHeadRoom < headroom && fBottom > fTop) fHeadRoom = headroom;
698 void TGHtmlLayoutContext::ComputeMargins(
int *pX,
int *pY,
int *pW)
702 y = fBottom + fHeadRoom;
703 PopExpiredMargins(&fLeftMargin, fBottom);
704 PopExpiredMargins(&fRightMargin, fBottom);
705 w = fPageWidth - fRight;
707 x = fLeftMargin->fIndent + fLeft;
712 if (fRightMargin) w -= fRightMargin->fIndent;
720 #define CLEAR_Right 1
722 #define CLEAR_First 3
735 void TGHtmlLayoutContext::ClearObstacle(
int mode)
737 int newBottom = fBottom;
739 PopExpiredMargins(&fLeftMargin, fBottom);
740 PopExpiredMargins(&fRightMargin, fBottom);
744 ClearObstacle(CLEAR_Left);
745 ClearObstacle(CLEAR_Right);
749 while (fLeftMargin && fLeftMargin->fBottom >= 0) {
750 if (newBottom < fLeftMargin->fBottom) {
751 newBottom = fLeftMargin->fBottom;
753 PopOneMargin(&fLeftMargin);
755 if (newBottom > fBottom + fHeadRoom) {
758 fHeadRoom = newBottom - fBottom;
761 PopExpiredMargins(&fRightMargin, fBottom);
765 while (fRightMargin && fRightMargin->fBottom >= 0) {
766 if (newBottom < fRightMargin->fBottom) {
767 newBottom = fRightMargin->fBottom;
769 PopOneMargin(&fRightMargin);
771 if (newBottom > fBottom + fHeadRoom) {
774 fHeadRoom = newBottom - fBottom;
777 PopExpiredMargins(&fLeftMargin, fBottom);
781 if (fLeftMargin && fLeftMargin->fBottom >= 0) {
783 fRightMargin->fBottom < fLeftMargin->fBottom) {
784 if (newBottom < fRightMargin->fBottom) {
785 newBottom = fRightMargin->fBottom;
787 PopOneMargin(&fRightMargin);
789 if (newBottom < fLeftMargin->fBottom) {
790 newBottom = fLeftMargin->fBottom;
792 PopOneMargin(&fLeftMargin);
794 }
else if (fRightMargin && fRightMargin->fBottom >= 0) {
795 newBottom = fRightMargin->fBottom;
796 PopOneMargin(&fRightMargin);
798 if (newBottom > fBottom + fHeadRoom) {
801 fHeadRoom = newBottom - fBottom;
814 int TGHtml::NextMarkupType(TGHtmlElement *p)
816 while ((p = p->fPNext)) {
817 if (p->IsMarkup())
return p->fType;
829 TGHtmlElement *TGHtmlLayoutContext::DoBreakMarkup(TGHtmlElement *p)
831 TGHtmlElement *fPNext = p->fPNext;
837 ((TGHtmlAnchor *)p)->fY = fBottom;
840 case Html_BLOCKQUOTE:
841 PushMargin(&fLeftMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
842 PushMargin(&fRightMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
846 case Html_EndBLOCKQUOTE:
847 PopMargin(&fLeftMargin, Html_EndBLOCKQUOTE);
848 PopMargin(&fRightMargin, Html_EndBLOCKQUOTE);
853 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
854 switch (image->fAlign) {
855 case IMAGE_ALIGN_Left:
856 ComputeMargins(&x, &y, &w);
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;
866 case IMAGE_ALIGN_Right:
867 ComputeMargins(&x, &y, &w);
868 image->fX = x + w - image->fW;
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;
886 while (fPNext->fType == Html_Space) {
887 TGHtmlElement *pThis = fPNext;
888 fPNext = fPNext->fPNext;
889 if (pThis->fFlags & HTML_NewLine)
break;
898 if (((TGHtmlListStart *)p)->fCompact == 0) Paragraph(p);
899 PushMargin(&fLeftMargin, HTML_INDENT, -1, p->fType + 1);
906 TGHtmlRef *ref = (TGHtmlRef *) p;
908 PopMargin(&fLeftMargin, p->fType);
909 if (!((TGHtmlListStart *)ref->fPOther)->fCompact) Paragraph(p);
916 PushMargin(&fLeftMargin, HTML_INDENT, -1, Html_EndDL);
920 PopMargin(&fLeftMargin, Html_EndDL);
926 TGHtmlHr *hr = (TGHtmlHr *) p;
927 hr->fIs3D = (p->MarkupArg(
"noshade", 0) == 0);
928 z = p->MarkupArg(
"size", 0);
931 hr->fH = (hrsz < 0) ? 2 : hrsz;
936 int relief = fHtml->GetRuleRelief();
938 (relief == HTML_RELIEF_SUNKEN || relief == HTML_RELIEF_RAISED)) {
944 ComputeMargins(&x, &y, &w);
945 hr->fY = y + fHtml->GetRulePadding();
946 y += hr->fH + fHtml->GetRulePadding() * 2 + 1;
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;
953 wd = z ? atoi(z) : w;
957 switch (p->fStyle.fAlign) {
960 hr->fX += (w - wd) / 2;
970 if (fMaxY < y) fMaxY = y;
971 if (fMaxX < wd + hr->fX) fMaxX = wd + hr->fX;
978 case Html_EndADDRESS:
1003 fPNext = TableLayout((TGHtmlTable *) p);
1007 z = p->MarkupArg(
"clear",0);
1009 if (strcasecmp(z,
"left") == 0) {
1010 ClearObstacle(CLEAR_Left);
1011 }
else if (strcasecmp(z,
"right") == 0) {
1012 ClearObstacle(CLEAR_Right);
1014 ClearObstacle(CLEAR_Both);
1017 if (p->fPNext && p->fPNext->fPNext && p->fPNext->fType == Html_Space &&
1018 p->fPNext->fPNext->fType == Html_BR) {
1046 int TGHtmlLayoutContext::InWrapAround()
1048 if (fLeftMargin && fLeftMargin->fBottom >= 0)
return 1;
1049 if (fRightMargin && fRightMargin->fBottom >= 0)
return 1;
1060 void TGHtmlLayoutContext::WidenLine(
int reqWidth,
int *pX,
int *pY,
int *pW)
1062 ComputeMargins(pX, pY, pW);
1063 if (*pW < reqWidth && InWrapAround()) {
1064 ClearObstacle(CLEAR_First);
1065 ComputeMargins(pX, pY, pW);
1070 #ifdef TABLE_TRIM_BLANK
1071 int HtmlLineWasBlank = 0;
1072 #endif // TABLE_TRIM_BLANK
1078 void TGHtmlLayoutContext::LayoutBlock()
1080 TGHtmlElement *p, *pNext;
1082 for (p = fPStart; p && p != fPEnd; p = pNext) {
1090 while (p && p != fPEnd) {
1091 pNext = DoBreakMarkup(p);
1092 if (pNext == p)
break;
1101 if (p == 0 || p == fPEnd)
break;
1103 #ifdef TABLE_TRIM_BLANK
1104 HtmlLineWasBlank = 0;
1105 #endif // TABLE_TRIM_BLANK
1111 ComputeMargins(&lMargin, &y, &lineWidth);
1114 pNext = GetLine(p, fPEnd, lineWidth, fLeft-lMargin, &actualWidth);
1118 FixAnchors(p, pNext, fBottom);
1124 if (actualWidth > lineWidth && InWrapAround()) {
1125 ClearObstacle(CLEAR_First);
1130 y = FixLine(p, pNext, y, lineWidth, actualWidth, lMargin, &max_x);
1134 #ifdef TABLE_TRIM_BLANK
1140 if (actualWidth <= 0) HtmlLineWasBlank = 1;
1142 #endif // TABLE_TRIM_BLANK
1145 if (pNext && actualWidth > 0 && y > fBottom) {
1150 if (y > fMaxY) fMaxY = y;
1151 if (max_x > fMaxX) fMaxX = max_x;
1158 void TGHtmlLayoutContext::PushIndent()
1160 fHeadRoom += fHtml->GetMarginHeight();
1161 if (fHtml->GetMarginWidth()) {
1162 PushMargin(&fLeftMargin, fHtml->GetMarginWidth(), -1, Html_EndBLOCKQUOTE);
1163 PushMargin(&fRightMargin, fHtml->GetMarginWidth(), -1, Html_EndBLOCKQUOTE);
1170 void TGHtmlLayoutContext::PopIndent()
1172 if (fHeadRoom <= 0)
return;
1174 PopMargin(&fRightMargin, Html_EndBLOCKQUOTE);
1180 void TGHtml::LayoutDoc()
1184 if (fPFirst == 0)
return;
1186 fLayoutContext.fHtml =
this;
1188 fLayoutContext.PushIndent();
1189 fLayoutContext.fPageWidth = fCanvas->GetWidth();
1190 fLayoutContext.fLeft = 0;
1192 fLayoutContext.fHeadRoom = HTML_INDENT/4;
1193 fLayoutContext.fPageWidth = fCanvas->GetWidth() - HTML_INDENT/4;
1194 fLayoutContext.fLeft = HTML_INDENT/4;
1196 fLayoutContext.fRight = 0;
1197 fLayoutContext.fPStart = fNextPlaced;
1198 if (fLayoutContext.fPStart == 0) fLayoutContext.fPStart = fPFirst;
1199 if (fLayoutContext.fPStart) {
1202 fLayoutContext.fMaxX = fMaxX;
1203 fLayoutContext.fMaxY = fMaxY;
1204 btm = fLayoutContext.fBottom;
1205 fLayoutContext.LayoutBlock();
1206 fMaxX = fLayoutContext.fMaxX;
1208 fMaxY = fLayoutContext.fMaxY;
1210 fMaxY = fLayoutContext.fMaxY + fYMargin;
1212 fNextPlaced = fLayoutContext.fPStart;
1213 fFlags |= HSCROLL | VSCROLL;
1214 if (fZGoto && (p = AttrElem(
"name", fZGoto+1))) {
1215 fVisible.fY = ((TGHtmlAnchor *)p)->fY;