00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <stdlib.h>
00030 #include <string.h>
00031
00032 #include "TGHtml.h"
00033
00034
00035
00036 TGHtmlLayoutContext::TGHtmlLayoutContext()
00037 {
00038
00039
00040 fPStart = 0;
00041 fPEnd = 0;
00042 fLeftMargin = 0;
00043 fRightMargin = 0;
00044 fHtml = 0;
00045 fLeft = 0;
00046 fRight = 0;
00047 fMaxX = 0;
00048 fMaxY = 0;
00049 fPageWidth = 0;
00050 Reset();
00051 }
00052
00053
00054 void TGHtmlLayoutContext::Reset()
00055 {
00056
00057
00058 fHeadRoom = 0;
00059 fTop = 0;
00060 fBottom = 0;
00061 ClearMarginStack(&fLeftMargin);
00062 ClearMarginStack(&fRightMargin);
00063 }
00064
00065
00066 void TGHtmlLayoutContext::PushMargin(SHtmlMargin_t **ppMargin,
00067 int indent, int mbottom, int tag)
00068 {
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 SHtmlMargin_t *pNew = new SHtmlMargin_t;
00085 pNew->fPNext = *ppMargin;
00086 if (pNew->fPNext) {
00087 pNew->fIndent = indent + pNew->fPNext->fIndent;
00088 } else {
00089 pNew->fIndent = indent;
00090 }
00091 pNew->fBottom = mbottom;
00092 pNew->fTag = tag;
00093 *ppMargin = pNew;
00094 }
00095
00096
00097 void TGHtmlLayoutContext::PopOneMargin(SHtmlMargin_t **ppMargin)
00098 {
00099
00100
00101 if (*ppMargin) {
00102 SHtmlMargin_t *pOld = *ppMargin;
00103 *ppMargin = pOld->fPNext;
00104 delete pOld;
00105 }
00106 }
00107
00108
00109 void TGHtmlLayoutContext::PopMargin(SHtmlMargin_t **ppMargin, int tag)
00110 {
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 int bot = -1;
00122 int oldTag;
00123 SHtmlMargin_t *pM;
00124
00125 for (pM = *ppMargin; pM && pM->fTag != tag; pM = pM->fPNext) {}
00126 if (pM == 0) {
00127
00128 return;
00129 }
00130 while ((pM = *ppMargin) != 0) {
00131 if (pM->fBottom > bot) bot = pM->fBottom;
00132 oldTag = pM->fTag;
00133 PopOneMargin(ppMargin);
00134 if (oldTag == tag) break;
00135 }
00136 if (fBottom < bot) {
00137 fHeadRoom += bot - fBottom;
00138 fBottom = bot;
00139 }
00140 }
00141
00142
00143 void TGHtmlLayoutContext::PopExpiredMargins(SHtmlMargin_t **ppMarginStack, int y)
00144 {
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 while (*ppMarginStack && (**ppMarginStack).fBottom >= 0 &&
00155 (**ppMarginStack).fBottom <= y) {
00156 PopOneMargin(ppMarginStack);
00157 }
00158 }
00159
00160
00161 void TGHtmlLayoutContext::ClearMarginStack(SHtmlMargin_t **ppMargin)
00162 {
00163
00164
00165
00166
00167 while (*ppMargin) PopOneMargin(ppMargin);
00168 }
00169
00170
00171 TGHtmlElement *TGHtmlLayoutContext::GetLine(TGHtmlElement *p_start,
00172 TGHtmlElement *p_end, int width, int minX, int *actualWidth)
00173 {
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 int x;
00207 int spaceWanted = 0;
00208 TGHtmlElement *p;
00209 TGHtmlElement *lastBreak = 0;
00210 int isEmpty = 1;
00211 int origin;
00212
00213 *actualWidth = 0;
00214 p = p_start;
00215 while (p && p != p_end && (p->fStyle.fFlags & STY_Invisible) != 0) {
00216 p = p->fPNext;
00217 }
00218 if (p && p->fStyle.fFlags & STY_DT) {
00219 origin = -HTML_INDENT;
00220 } else {
00221 origin = 0;
00222 }
00223 x = origin;
00224 if (x < minX) x = minX;
00225 if (p && p != p_end && p->fType == Html_LI) {
00226 TGHtmlLi *li = (TGHtmlLi *) p;
00227 li->fX = x - HTML_INDENT / 3;
00228 if (li->fX - (HTML_INDENT * 2) / 3 < minX) {
00229 x += minX - li->fX + (HTML_INDENT * 2) / 3;
00230 li->fX = minX + (HTML_INDENT * 2) / 3;
00231 }
00232 isEmpty = 0;
00233 *actualWidth = 1;
00234 p = p->fPNext;
00235 while (p && (p->fType == Html_Space || p->fType == Html_P)) {
00236 p = p->fPNext;
00237 }
00238 }
00239 for (; p && p != p_end; p = p ? p->fPNext : 0) {
00240 if (p->fStyle.fFlags & STY_Invisible) continue;
00241 switch (p->fType) {
00242 case Html_Text: {
00243 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
00244 text->fX = x + spaceWanted;
00245 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
00246 if (lastBreak && x + spaceWanted + text->fW > width)
00247 return lastBreak;
00248 }
00249
00250
00251 x += text->fW + spaceWanted;
00252 isEmpty = 0;
00253 spaceWanted = 0;
00254 break;
00255 }
00256
00257 case Html_Space: {
00258 TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
00259 if (p->fStyle.fFlags & STY_Preformatted) {
00260 if (p->fFlags & HTML_NewLine) {
00261 *actualWidth = (x <= 0) ? 1 : x;
00262 return p->fPNext;
00263 }
00264 x += space->fW * p->fCount;
00265 } else {
00266 int w;
00267 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
00268 lastBreak = p->fPNext;
00269 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00270 }
00271 w = space->fW;
00272 if (spaceWanted < w && x > origin) spaceWanted = w;
00273 }
00274 break;
00275 }
00276
00277 case Html_IMG: {
00278 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
00279 switch (image->fAlign) {
00280 case IMAGE_ALIGN_Left:
00281 case IMAGE_ALIGN_Right:
00282 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00283 return p;
00284 default:
00285 break;
00286 }
00287 image->fX = x + spaceWanted;
00288 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
00289 if (lastBreak && x + spaceWanted + image->fW > width) {
00290 return lastBreak;
00291 }
00292 }
00293
00294
00295 x += image->fW + spaceWanted;
00296 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
00297 lastBreak = p->fPNext;
00298 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00299 }
00300 spaceWanted = 0;
00301 isEmpty = 0;
00302 break;
00303 }
00304
00305 case Html_APPLET:
00306 case Html_EMBED:
00307 case Html_INPUT:
00308 case Html_SELECT:
00309 case Html_TEXTAREA: {
00310 TGHtmlInput *input = (TGHtmlInput *) p;
00311 input->fX = x + spaceWanted + input->fPadLeft;
00312 if ((p->fStyle.fFlags & STY_Preformatted) == 0) {
00313 if (lastBreak && x + spaceWanted + input->fW > width) {
00314 return lastBreak;
00315 }
00316 }
00317
00318
00319 x = input->fX + input->fW;
00320 if ((p->fStyle.fFlags & STY_NoBreak) == 0) {
00321 lastBreak = p->fPNext;
00322 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00323 }
00324 spaceWanted = 0;
00325 isEmpty = 0;
00326 break;
00327 }
00328
00329 case Html_EndTEXTAREA: {
00330 TGHtmlRef *ref = (TGHtmlRef *) p;
00331 if (ref->fPOther) {
00332
00333 }
00334 break;
00335 }
00336
00337 case Html_DD: {
00338 TGHtmlRef *ref = (TGHtmlRef *) p;
00339 if (ref->fPOther == 0) break;
00340 if (((TGHtmlListStart *)ref->fPOther)->fCompact == 0 ||
00341 x + spaceWanted >= 0) {
00342 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00343 return p;
00344 }
00345 x = 0;
00346 spaceWanted = 0;
00347 break;
00348 }
00349
00350 case Html_WBR:
00351 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00352 if (x + spaceWanted >= width) {
00353 return p->fPNext;
00354 } else {
00355 lastBreak = p->fPNext;
00356 }
00357 break;
00358
00359 case Html_ADDRESS:
00360 case Html_EndADDRESS:
00361 case Html_BLOCKQUOTE:
00362 case Html_EndBLOCKQUOTE:
00363 case Html_BODY:
00364 case Html_EndBODY:
00365 case Html_BR:
00366 case Html_CAPTION:
00367 case Html_EndCAPTION:
00368 case Html_CENTER:
00369 case Html_EndCENTER:
00370 case Html_EndDD:
00371 case Html_DIV:
00372 case Html_EndDIV:
00373 case Html_DL:
00374 case Html_EndDL:
00375 case Html_DT:
00376 case Html_H1:
00377 case Html_EndH1:
00378 case Html_H2:
00379 case Html_EndH2:
00380 case Html_H3:
00381 case Html_EndH3:
00382 case Html_H4:
00383 case Html_EndH4:
00384 case Html_H5:
00385 case Html_EndH5:
00386 case Html_H6:
00387 case Html_EndH6:
00388 case Html_EndHTML:
00389 case Html_HR:
00390 case Html_LI:
00391 case Html_LISTING:
00392 case Html_EndLISTING:
00393 case Html_MENU:
00394 case Html_EndMENU:
00395 case Html_OL:
00396 case Html_EndOL:
00397 case Html_P:
00398 case Html_EndP:
00399 case Html_PRE:
00400 case Html_EndPRE:
00401 case Html_TABLE:
00402 case Html_EndTABLE:
00403 case Html_TD:
00404 case Html_EndTD:
00405 case Html_TH:
00406 case Html_EndTH:
00407 case Html_TR:
00408 case Html_EndTR:
00409 case Html_UL:
00410 case Html_EndUL:
00411 case Html_EndFORM:
00412 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00413 return p;
00414
00415 default:
00416 break;
00417 }
00418 }
00419 *actualWidth = ((x <= 0) && !isEmpty) ? 1 : x;
00420
00421 return p;
00422 }
00423
00424
00425 void TGHtmlLayoutContext::FixAnchors(TGHtmlElement *p, TGHtmlElement *p_end, int y)
00426 {
00427
00428
00429 while (p && p != p_end) {
00430 if (p->fType == Html_A) ((TGHtmlAnchor *)p)->fY = y;
00431 p = p->fPNext;
00432 }
00433 }
00434
00435
00436 int TGHtmlLayoutContext::FixLine(TGHtmlElement *p_start,
00437 TGHtmlElement *p_end, int mbottom, int width,
00438 int actualWidth, int lMargin, int *max_x)
00439 {
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 int dx;
00457 int maxAscent;
00458 int maxTextAscent;
00459 int maxDescent;
00460 int ascent, descent;
00461 TGHtmlElement *p;
00462 int y;
00463 int dy2center;
00464 int max = 0;
00465
00466 if (actualWidth > 0) {
00467 for (p = p_start; p && p != p_end && p->fType != Html_Text; p = p->fPNext) {}
00468 if (p == p_end || p == 0) p = p_start;
00469 maxAscent = maxTextAscent = 0;
00470 for (p = p_start; p && p != p_end; p = p->fPNext) {
00471 int ss;
00472 if (p->fStyle.fAlign == ALIGN_Center) {
00473 dx = lMargin + (width - actualWidth) / 2;
00474 } else if (p->fStyle.fAlign == ALIGN_Right) {
00475 dx = lMargin + (width - actualWidth);
00476 } else {
00477 dx = lMargin;
00478 }
00479 if (dx < 0) dx = 0;
00480 if (p->fStyle.fFlags & STY_Invisible) continue;
00481 switch (p->fType) {
00482 case Html_Text: {
00483 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
00484 text->fX += dx;
00485 max = text->fX + text->fW;
00486 ss = p->fStyle.fSubscript;
00487 if (ss > 0) {
00488 int ascent2 = text->fAscent;
00489 int delta = (ascent2 + text->fDescent) * ss / 2;
00490 ascent2 += delta;
00491 text->fY = -delta;
00492 if (ascent2 > maxAscent) maxAscent = ascent2;
00493 if (ascent2 > maxTextAscent) maxTextAscent = ascent2;
00494 } else if (ss < 0) {
00495 int descent2 = text->fDescent;
00496 int delta = (descent2 + text->fAscent) * (-ss) / 2;
00497 descent2 += delta;
00498 text->fY = delta;
00499 } else {
00500 text->fY = 0;
00501 if (text->fAscent > maxAscent) maxAscent = text->fAscent;
00502 if (text->fAscent > maxTextAscent) maxTextAscent = text->fAscent;
00503 }
00504 break;
00505 }
00506
00507 case Html_Space: {
00508 TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
00509 if (space->fAscent > maxAscent) maxAscent = space->fAscent;
00510 break;
00511 }
00512
00513 case Html_LI: {
00514 TGHtmlLi *li = (TGHtmlLi *) p;
00515 li->fX += dx;
00516 if (li->fX > max) max = li->fX;
00517 break;
00518 }
00519
00520 case Html_IMG: {
00521 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
00522 image->fX += dx;
00523 max = image->fX + image->fW;
00524 switch (image->fAlign) {
00525 case IMAGE_ALIGN_Middle:
00526 image->fDescent = image->fH / 2;
00527 image->fAscent = image->fH - image->fDescent;
00528 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
00529 break;
00530
00531 case IMAGE_ALIGN_AbsMiddle:
00532 dy2center = (image->fTextDescent - image->fTextAscent) / 2;
00533 image->fDescent = image->fH / 2 + dy2center;
00534 image->fAscent = image->fH - image->fDescent;
00535 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
00536 break;
00537
00538 case IMAGE_ALIGN_Bottom:
00539 image->fDescent = 0;
00540 image->fAscent = image->fH;
00541 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
00542 break;
00543
00544 case IMAGE_ALIGN_AbsBottom:
00545 image->fDescent = image->fTextDescent;
00546 image->fAscent = image->fH - image->fDescent;
00547 if (image->fAscent > maxAscent) maxAscent = image->fAscent;
00548 break;
00549
00550 default:
00551 break;
00552 }
00553 break;
00554 }
00555
00556 case Html_TABLE:
00557 break;
00558
00559 case Html_TEXTAREA:
00560 case Html_INPUT:
00561 case Html_SELECT:
00562 case Html_EMBED:
00563 case Html_APPLET: {
00564 TGHtmlInput *input = (TGHtmlInput *) p;
00565 input->fX += dx;
00566 max = input->fX + input->fW;
00567 dy2center = (input->fTextDescent - input->fTextAscent) / 2;
00568 input->fY = dy2center - input->fH / 2;
00569 ascent = -input->fY;
00570 if (ascent > maxAscent) maxAscent = ascent;
00571 break;
00572 }
00573
00574 default:
00575
00576 break;
00577 }
00578 }
00579
00580 *max_x = max;
00581 y = maxAscent + mbottom;
00582 maxDescent = 0;
00583
00584 for (p = p_start; p && p != p_end; p = p->fPNext) {
00585 if (p->fStyle.fFlags & STY_Invisible) continue;
00586 switch (p->fType) {
00587 case Html_Text: {
00588 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
00589 text->fY += y;
00590 if (text->fDescent > maxDescent) maxDescent = text->fDescent;
00591 break;
00592 }
00593
00594 case Html_LI: {
00595 TGHtmlLi *li = (TGHtmlLi *) p;
00596 li->fY = y;
00597 if (li->fDescent > maxDescent) maxDescent = li->fDescent;
00598 break;
00599 }
00600
00601 case Html_IMG: {
00602 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
00603 image->fY = y;
00604 switch (image->fAlign) {
00605 case IMAGE_ALIGN_Top:
00606 image->fAscent = maxAscent;
00607 image->fDescent = image->fH - maxAscent;
00608 break;
00609
00610 case IMAGE_ALIGN_TextTop:
00611 image->fAscent = maxTextAscent;
00612 image->fDescent = image->fH - maxTextAscent;
00613 break;
00614
00615 default:
00616 break;
00617 }
00618 if (image->fDescent > maxDescent) maxDescent = image->fDescent;
00619 break;
00620 }
00621
00622 case Html_TABLE:
00623 break;
00624
00625 case Html_INPUT:
00626 case Html_SELECT:
00627 case Html_TEXTAREA:
00628 case Html_APPLET:
00629 case Html_EMBED: {
00630 TGHtmlInput *input = (TGHtmlInput *) p;
00631 descent = input->fY + input->fH;
00632 input->fY += y;
00633 if (descent > maxDescent) maxDescent = descent;
00634 break;
00635 }
00636
00637 default:
00638
00639 break;
00640 }
00641 }
00642
00643
00644
00645
00646
00647 } else {
00648 maxDescent = 0;
00649 y = mbottom;
00650 }
00651
00652 return y + maxDescent;
00653 }
00654
00655
00656 void TGHtmlLayoutContext::Paragraph(TGHtmlElement *p)
00657 {
00658
00659
00660 int headroom;
00661
00662 if (p == 0) return;
00663
00664 if (p->fType == Html_Text) {
00665 TGHtmlTextElement *text = (TGHtmlTextElement *) p;
00666 headroom = text->fAscent + text->fDescent;
00667 } else if (p->fPNext && p->fPNext->fType == Html_Text) {
00668 TGHtmlTextElement *text = (TGHtmlTextElement *) p->fPNext;
00669 headroom = text->fAscent + text->fDescent;
00670 } else {
00671
00672 FontMetrics_t fontMetrics;
00673 TGFont *font;
00674 font = fHtml->GetFont(p->fStyle.fFont);
00675 if (font == 0) return;
00676 font->GetFontMetrics(&fontMetrics);
00677 headroom = fontMetrics.fDescent + fontMetrics.fAscent;
00678 }
00679 if (fHeadRoom < headroom && fBottom > fTop) fHeadRoom = headroom;
00680 }
00681
00682
00683 void TGHtmlLayoutContext::ComputeMargins(int *pX, int *pY, int *pW)
00684 {
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699 int x, y, w;
00700
00701 y = fBottom + fHeadRoom;
00702 PopExpiredMargins(&fLeftMargin, fBottom);
00703 PopExpiredMargins(&fRightMargin, fBottom);
00704 w = fPageWidth - fRight;
00705 if (fLeftMargin) {
00706 x = fLeftMargin->fIndent + fLeft;
00707 } else {
00708 x = fLeft;
00709 }
00710 w -= x;
00711 if (fRightMargin) w -= fRightMargin->fIndent;
00712
00713 *pX = x;
00714 *pY = y;
00715 *pW = w;
00716 }
00717
00718 #define CLEAR_Left 0
00719 #define CLEAR_Right 1
00720 #define CLEAR_Both 2
00721 #define CLEAR_First 3
00722
00723 void TGHtmlLayoutContext::ClearObstacle(int mode)
00724 {
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736 int newBottom = fBottom;
00737
00738 PopExpiredMargins(&fLeftMargin, fBottom);
00739 PopExpiredMargins(&fRightMargin, fBottom);
00740
00741 switch (mode) {
00742 case CLEAR_Both:
00743 ClearObstacle(CLEAR_Left);
00744 ClearObstacle(CLEAR_Right);
00745 break;
00746
00747 case CLEAR_Left:
00748 while (fLeftMargin && fLeftMargin->fBottom >= 0) {
00749 if (newBottom < fLeftMargin->fBottom) {
00750 newBottom = fLeftMargin->fBottom;
00751 }
00752 PopOneMargin(&fLeftMargin);
00753 }
00754 if (newBottom > fBottom + fHeadRoom) {
00755 fHeadRoom = 0;
00756 } else {
00757 fHeadRoom = newBottom - fBottom;
00758 }
00759 fBottom = newBottom;
00760 PopExpiredMargins(&fRightMargin, fBottom);
00761 break;
00762
00763 case CLEAR_Right:
00764 while (fRightMargin && fRightMargin->fBottom >= 0) {
00765 if (newBottom < fRightMargin->fBottom) {
00766 newBottom = fRightMargin->fBottom;
00767 }
00768 PopOneMargin(&fRightMargin);
00769 }
00770 if (newBottom > fBottom + fHeadRoom) {
00771 fHeadRoom = 0;
00772 } else {
00773 fHeadRoom = newBottom - fBottom;
00774 }
00775 fBottom = newBottom;
00776 PopExpiredMargins(&fLeftMargin, fBottom);
00777 break;
00778
00779 case CLEAR_First:
00780 if (fLeftMargin && fLeftMargin->fBottom >= 0) {
00781 if (fRightMargin &&
00782 fRightMargin->fBottom < fLeftMargin->fBottom) {
00783 if (newBottom < fRightMargin->fBottom) {
00784 newBottom = fRightMargin->fBottom;
00785 }
00786 PopOneMargin(&fRightMargin);
00787 } else {
00788 if (newBottom < fLeftMargin->fBottom) {
00789 newBottom = fLeftMargin->fBottom;
00790 }
00791 PopOneMargin(&fLeftMargin);
00792 }
00793 } else if (fRightMargin && fRightMargin->fBottom >= 0) {
00794 newBottom = fRightMargin->fBottom;
00795 PopOneMargin(&fRightMargin);
00796 }
00797 if (newBottom > fBottom + fHeadRoom) {
00798 fHeadRoom = 0;
00799 } else {
00800 fHeadRoom = newBottom - fBottom;
00801 }
00802 fBottom = newBottom;
00803 break;
00804
00805 default:
00806 break;
00807 }
00808 }
00809
00810
00811 int TGHtml::NextMarkupType(TGHtmlElement *p)
00812 {
00813
00814
00815 while ((p = p->fPNext)) {
00816 if (p->IsMarkup()) return p->fType;
00817 }
00818 return Html_Unknown;
00819 }
00820
00821
00822 TGHtmlElement *TGHtmlLayoutContext::DoBreakMarkup(TGHtmlElement *p)
00823 {
00824
00825
00826
00827
00828
00829
00830 TGHtmlElement *fPNext = p->fPNext;
00831 const char *z;
00832 int x, y, w;
00833
00834 switch (p->fType) {
00835 case Html_A:
00836 ((TGHtmlAnchor *)p)->fY = fBottom;
00837 break;
00838
00839 case Html_BLOCKQUOTE:
00840 PushMargin(&fLeftMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
00841 PushMargin(&fRightMargin, HTML_INDENT, -1, Html_EndBLOCKQUOTE);
00842 Paragraph(p);
00843 break;
00844
00845 case Html_EndBLOCKQUOTE:
00846 PopMargin(&fLeftMargin, Html_EndBLOCKQUOTE);
00847 PopMargin(&fRightMargin, Html_EndBLOCKQUOTE);
00848 Paragraph(p);
00849 break;
00850
00851 case Html_IMG: {
00852 TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
00853 switch (image->fAlign) {
00854 case IMAGE_ALIGN_Left:
00855 ComputeMargins(&x, &y, &w);
00856 image->fX = x;
00857 image->fY = y;
00858 image->fAscent = 0;
00859 image->fDescent = image->fH;
00860 PushMargin(&fLeftMargin, image->fW + 2, y + image->fH, 0);
00861 if (fMaxY < y + image->fH) fMaxY = y + image->fH;
00862 if (fMaxX < x + image->fW) fMaxX = x + image->fW;
00863 break;
00864
00865 case IMAGE_ALIGN_Right:
00866 ComputeMargins(&x, &y, &w);
00867 image->fX = x + w - image->fW;
00868 image->fY = y;
00869 image->fAscent = 0;
00870 image->fDescent = image->fH;
00871 PushMargin(&fRightMargin, image->fW + 2, y + image->fH, 0);
00872 if (fMaxY < y + image->fH) fMaxY = y + image->fH;
00873 if (fMaxX < x + image->fW) fMaxX = x + image->fW;
00874 break;
00875
00876 default:
00877 fPNext = p;
00878 break;
00879 }
00880 break;
00881 }
00882
00883 case Html_PRE:
00884
00885 while (fPNext->fType == Html_Space) {
00886 TGHtmlElement *pThis = fPNext;
00887 fPNext = fPNext->fPNext;
00888 if (pThis->fFlags & HTML_NewLine) break;
00889 }
00890 Paragraph(p);
00891 break;
00892
00893 case Html_UL:
00894 case Html_MENU:
00895 case Html_DIR:
00896 case Html_OL:
00897 if (((TGHtmlListStart *)p)->fCompact == 0) Paragraph(p);
00898 PushMargin(&fLeftMargin, HTML_INDENT, -1, p->fType + 1);
00899 break;
00900
00901 case Html_EndOL:
00902 case Html_EndUL:
00903 case Html_EndMENU:
00904 case Html_EndDIR: {
00905 TGHtmlRef *ref = (TGHtmlRef *) p;
00906 if (ref->fPOther) {
00907 PopMargin(&fLeftMargin, p->fType);
00908 if (!((TGHtmlListStart *)ref->fPOther)->fCompact) Paragraph(p);
00909 }
00910 break;
00911 }
00912
00913 case Html_DL:
00914 Paragraph(p);
00915 PushMargin(&fLeftMargin, HTML_INDENT, -1, Html_EndDL);
00916 break;
00917
00918 case Html_EndDL:
00919 PopMargin(&fLeftMargin, Html_EndDL);
00920 Paragraph(p);
00921 break;
00922
00923 case Html_HR: {
00924 int zl, wd;
00925 TGHtmlHr *hr = (TGHtmlHr *) p;
00926 hr->fIs3D = (p->MarkupArg("noshade", 0) == 0);
00927 z = p->MarkupArg("size", 0);
00928 if (z) {
00929 int hrsz = atoi(z);
00930 hr->fH = (hrsz < 0) ? 2 : hrsz;
00931 } else {
00932 hr->fH = 0;
00933 }
00934 if (hr->fH < 1) {
00935 int relief = fHtml->GetRuleRelief();
00936 if (hr->fIs3D &&
00937 (relief == HTML_RELIEF_SUNKEN || relief == HTML_RELIEF_RAISED)) {
00938 hr->fH = 3;
00939 } else {
00940 hr->fH = 2;
00941 }
00942 }
00943 ComputeMargins(&x, &y, &w);
00944 hr->fY = y + fHtml->GetRulePadding();
00945 y += hr->fH + fHtml->GetRulePadding() * 2 + 1;
00946 hr->fX = x;
00947 z = p->MarkupArg("width", "100%");
00948 zl = strlen(z);
00949 if (zl > 0 && z[zl-1] == '%') {
00950 wd = (atoi(z) * w) / 100;
00951 } else {
00952 wd = atoi(z);
00953 }
00954 if (wd > w) wd = w;
00955 hr->fW = wd;
00956 switch (p->fStyle.fAlign) {
00957 case ALIGN_Center:
00958 case ALIGN_None:
00959 hr->fX += (w - wd) / 2;
00960 break;
00961
00962 case ALIGN_Right:
00963 hr->fX += (w - wd);
00964 break;
00965
00966 default:
00967 break;
00968 }
00969 if (fMaxY < y) fMaxY = y;
00970 if (fMaxX < wd + hr->fX) fMaxX = wd + hr->fX;
00971 fBottom = y;
00972 fHeadRoom = 0;
00973 break;
00974 }
00975
00976 case Html_ADDRESS:
00977 case Html_EndADDRESS:
00978 case Html_CENTER:
00979 case Html_EndCENTER:
00980 case Html_DIV:
00981 case Html_EndDIV:
00982 case Html_H1:
00983 case Html_EndH1:
00984 case Html_H2:
00985 case Html_EndH2:
00986 case Html_H3:
00987 case Html_EndH3:
00988 case Html_H4:
00989 case Html_EndH4:
00990 case Html_H5:
00991 case Html_EndH5:
00992 case Html_H6:
00993 case Html_EndH6:
00994 case Html_P:
00995 case Html_EndP:
00996 case Html_EndPRE:
00997 case Html_EndFORM:
00998 Paragraph(p);
00999 break;
01000
01001 case Html_TABLE:
01002 fPNext = TableLayout((TGHtmlTable *) p);
01003 break;
01004
01005 case Html_BR:
01006 z = p->MarkupArg("clear",0);
01007 if (z) {
01008 if (strcasecmp(z, "left") == 0) {
01009 ClearObstacle(CLEAR_Left);
01010 } else if (strcasecmp(z, "right") == 0) {
01011 ClearObstacle(CLEAR_Right);
01012 } else {
01013 ClearObstacle(CLEAR_Both);
01014 }
01015 }
01016 if (p->fPNext && p->fPNext->fPNext && p->fPNext->fType == Html_Space &&
01017 p->fPNext->fPNext->fType == Html_BR) {
01018 Paragraph(p);
01019 }
01020 break;
01021
01022
01023 case Html_Text:
01024 case Html_Space:
01025 case Html_LI:
01026 case Html_INPUT:
01027 case Html_SELECT:
01028 case Html_TEXTAREA:
01029 case Html_APPLET:
01030 case Html_EMBED:
01031 fPNext = p;
01032 break;
01033
01034 default:
01035 break;
01036 }
01037
01038 return fPNext;
01039 }
01040
01041
01042 int TGHtmlLayoutContext::InWrapAround()
01043 {
01044
01045
01046
01047 if (fLeftMargin && fLeftMargin->fBottom >= 0) return 1;
01048 if (fRightMargin && fRightMargin->fBottom >= 0) return 1;
01049 return 0;
01050 }
01051
01052
01053 void TGHtmlLayoutContext::WidenLine(int reqWidth, int *pX, int *pY, int *pW)
01054 {
01055
01056
01057
01058
01059
01060
01061 ComputeMargins(pX, pY, pW);
01062 if (*pW < reqWidth && InWrapAround()) {
01063 ClearObstacle(CLEAR_First);
01064 ComputeMargins(pX, pY, pW);
01065 }
01066 }
01067
01068
01069 #ifdef TABLE_TRIM_BLANK
01070 int HtmlLineWasBlank = 0;
01071 #endif // TABLE_TRIM_BLANK
01072
01073
01074 void TGHtmlLayoutContext::LayoutBlock()
01075 {
01076
01077
01078
01079 TGHtmlElement *p, *pNext;
01080
01081 for (p = fPStart; p && p != fPEnd; p = pNext) {
01082 int lineWidth;
01083 int actualWidth;
01084 int y = 0;
01085 int lMargin;
01086 int max_x = 0;
01087
01088
01089 while (p && p != fPEnd) {
01090 pNext = DoBreakMarkup(p);
01091 if (pNext == p) break;
01092 if (pNext) {
01093
01094
01095 fPStart = p;
01096 }
01097 p = pNext;
01098 }
01099
01100 if (p == 0 || p == fPEnd) break;
01101
01102 #ifdef TABLE_TRIM_BLANK
01103 HtmlLineWasBlank = 0;
01104 #endif // TABLE_TRIM_BLANK
01105
01106
01107 while (1) {
01108
01109
01110 ComputeMargins(&lMargin, &y, &lineWidth);
01111
01112
01113 pNext = GetLine(p, fPEnd, lineWidth, fLeft-lMargin, &actualWidth);
01114
01115
01116
01117 FixAnchors(p, pNext, fBottom);
01118
01119
01120
01121
01122
01123 if (actualWidth > lineWidth && InWrapAround()) {
01124 ClearObstacle(CLEAR_First);
01125 continue;
01126 }
01127
01128
01129 y = FixLine(p, pNext, y, lineWidth, actualWidth, lMargin, &max_x);
01130 break;
01131 }
01132
01133 #ifdef TABLE_TRIM_BLANK
01134
01135
01136
01137
01138
01139 if (actualWidth <= 0) HtmlLineWasBlank = 1;
01140
01141 #endif // TABLE_TRIM_BLANK
01142
01143
01144 if (pNext && actualWidth > 0 && y > fBottom) {
01145 PopIndent();
01146 fBottom = y;
01147 fPStart = pNext;
01148 }
01149 if (y > fMaxY) fMaxY = y;
01150 if (max_x > fMaxX) fMaxX = max_x;
01151 }
01152 }
01153
01154
01155 void TGHtmlLayoutContext::PushIndent()
01156 {
01157
01158
01159 fHeadRoom += fHtml->GetMarginHeight();
01160 if (fHtml->GetMarginWidth()) {
01161 PushMargin(&fLeftMargin, fHtml->GetMarginWidth(), -1, Html_EndBLOCKQUOTE);
01162 PushMargin(&fRightMargin, fHtml->GetMarginWidth(), -1, Html_EndBLOCKQUOTE);
01163 }
01164 }
01165
01166
01167 void TGHtmlLayoutContext::PopIndent()
01168 {
01169
01170
01171 if (fHeadRoom <= 0) return;
01172 fHeadRoom = 0;
01173 PopMargin(&fRightMargin, Html_EndBLOCKQUOTE);
01174 }
01175
01176
01177 void TGHtml::LayoutDoc()
01178 {
01179
01180
01181 int btm;
01182
01183 if (fPFirst == 0) return;
01184 Sizer();
01185 fLayoutContext.fHtml = this;
01186 #if 0 // orig
01187 fLayoutContext.PushIndent();
01188 fLayoutContext.fPageWidth = fCanvas->GetWidth();
01189 fLayoutContext.fLeft = 0;
01190 #else
01191 fLayoutContext.fHeadRoom = HTML_INDENT/4;
01192 fLayoutContext.fPageWidth = fCanvas->GetWidth() - HTML_INDENT/4;
01193 fLayoutContext.fLeft = HTML_INDENT/4;
01194 #endif
01195 fLayoutContext.fRight = 0;
01196 fLayoutContext.fPStart = fNextPlaced;
01197 if (fLayoutContext.fPStart == 0) fLayoutContext.fPStart = fPFirst;
01198 if (fLayoutContext.fPStart) {
01199 TGHtmlElement *p;
01200
01201 fLayoutContext.fMaxX = fMaxX;
01202 fLayoutContext.fMaxY = fMaxY;
01203 btm = fLayoutContext.fBottom;
01204 fLayoutContext.LayoutBlock();
01205 fMaxX = fLayoutContext.fMaxX;
01206 #if 0
01207 fMaxY = fLayoutContext.fMaxY;
01208 #else
01209 fMaxY = fLayoutContext.fMaxY + fYMargin;
01210 #endif
01211 fNextPlaced = fLayoutContext.fPStart;
01212 fFlags |= HSCROLL | VSCROLL;
01213 if (fZGoto && (p = AttrElem("name", fZGoto+1))) {
01214 fVisible.fY = ((TGHtmlAnchor *)p)->fY;
01215 delete[] fZGoto;
01216 fZGoto = 0;
01217 }
01218 RedrawText(btm);
01219 }
01220 }